2013-10-25 15:19:00 +00:00
|
|
|
/*
|
2013-12-20 19:25:49 +00:00
|
|
|
* This is the source code of Telegram for Android v. 1.3.2.
|
2013-10-25 15:19:00 +00:00
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package org.telegram.messenger;
|
|
|
|
|
|
|
|
import java.io.File;
|
|
|
|
import java.io.FileInputStream;
|
|
|
|
import java.math.BigInteger;
|
|
|
|
import java.security.MessageDigest;
|
|
|
|
import java.security.NoSuchAlgorithmException;
|
|
|
|
import java.util.Locale;
|
|
|
|
|
|
|
|
public class FileUploadOperation {
|
2013-10-26 22:34:39 +00:00
|
|
|
private int uploadChunkSize = 1024 * 32;
|
2013-10-25 15:19:00 +00:00
|
|
|
private String uploadingFilePath;
|
|
|
|
public int state = 0;
|
2013-10-26 22:34:39 +00:00
|
|
|
private byte[] readBuffer;
|
2013-10-25 15:19:00 +00:00
|
|
|
public FileUploadOperationDelegate delegate;
|
|
|
|
private long requestToken = 0;
|
|
|
|
private int currentPartNum = 0;
|
|
|
|
private long currentFileId;
|
|
|
|
private boolean isLastPart = false;
|
|
|
|
private long totalFileSize = 0;
|
2013-12-20 19:25:49 +00:00
|
|
|
private int totalPartsCount = 0;
|
2013-10-25 15:19:00 +00:00
|
|
|
private long currentUploaded = 0;
|
|
|
|
private byte[] key;
|
|
|
|
private byte[] iv;
|
|
|
|
private int fingerprint;
|
2013-12-20 19:25:49 +00:00
|
|
|
private boolean isBigFile = false;
|
2013-10-25 15:19:00 +00:00
|
|
|
FileInputStream stream;
|
|
|
|
MessageDigest mdEnc = null;
|
|
|
|
|
|
|
|
public static interface FileUploadOperationDelegate {
|
2013-12-20 19:25:49 +00:00
|
|
|
public abstract void didFinishUploadingFile(FileUploadOperation operation, TLRPC.InputFile inputFile, TLRPC.InputEncryptedFile inputEncryptedFile);
|
2013-10-25 15:19:00 +00:00
|
|
|
public abstract void didFailedUploadingFile(FileUploadOperation operation);
|
|
|
|
public abstract void didChangedUploadProgress(FileUploadOperation operation, float progress);
|
|
|
|
}
|
|
|
|
|
|
|
|
public FileUploadOperation(String location, byte[] keyarr, byte[] ivarr) {
|
|
|
|
uploadingFilePath = location;
|
|
|
|
if (ivarr != null && keyarr != null) {
|
|
|
|
iv = new byte[32];
|
|
|
|
key = keyarr;
|
|
|
|
System.arraycopy(ivarr, 0, iv, 0, 32);
|
|
|
|
try {
|
|
|
|
java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
|
|
|
|
byte[] arr = new byte[64];
|
|
|
|
System.arraycopy(key, 0, arr, 0, 32);
|
|
|
|
System.arraycopy(iv, 0, arr, 32, 32);
|
|
|
|
byte[] digest = md.digest(arr);
|
|
|
|
byte[] fingerprintBytes = new byte[4];
|
|
|
|
for (int a = 0; a < 4; a++) {
|
|
|
|
fingerprintBytes[a] = (byte)(digest[a] ^ digest[a + 4]);
|
|
|
|
}
|
|
|
|
fingerprint = Utilities.bytesToInt(fingerprintBytes);
|
|
|
|
} catch (Exception e) {
|
2013-12-20 19:25:49 +00:00
|
|
|
FileLog.e("tmessages", e);
|
2013-10-25 15:19:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
currentFileId = (long)(MessagesController.random.nextDouble() * Long.MAX_VALUE);
|
|
|
|
try {
|
|
|
|
mdEnc = MessageDigest.getInstance("MD5");
|
|
|
|
} catch (NoSuchAlgorithmException e) {
|
2013-12-20 19:25:49 +00:00
|
|
|
FileLog.e("tmessages", e);
|
2013-10-25 15:19:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void start() {
|
|
|
|
if (state != 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
state = 1;
|
|
|
|
startUploadRequest();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void cancel() {
|
|
|
|
if (state != 1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
state = 2;
|
|
|
|
if (requestToken != 0) {
|
|
|
|
ConnectionsManager.Instance.cancelRpc(requestToken, true);
|
|
|
|
}
|
|
|
|
delegate.didFailedUploadingFile(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void startUploadRequest() {
|
|
|
|
if (state != 1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-12-20 19:25:49 +00:00
|
|
|
TLObject finalRequest;
|
|
|
|
|
2013-10-25 15:19:00 +00:00
|
|
|
try {
|
|
|
|
if (stream == null) {
|
|
|
|
File cacheFile = new File(uploadingFilePath);
|
|
|
|
stream = new FileInputStream(cacheFile);
|
|
|
|
totalFileSize = cacheFile.length();
|
2013-12-20 19:25:49 +00:00
|
|
|
if (totalFileSize > 10 * 1024 * 1024) {
|
|
|
|
FileLog.e("tmessages", "file is big!");
|
|
|
|
isBigFile = true;
|
|
|
|
}
|
2013-10-26 22:34:39 +00:00
|
|
|
|
2014-02-04 18:36:55 +00:00
|
|
|
uploadChunkSize = (int)Math.max(32, Math.ceil(totalFileSize / (1024.0f * 3000)));
|
|
|
|
if (1024 % uploadChunkSize != 0) {
|
|
|
|
int chunkSize = 64;
|
|
|
|
while (uploadChunkSize > chunkSize) {
|
|
|
|
chunkSize *= 2;
|
|
|
|
}
|
|
|
|
uploadChunkSize = chunkSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
uploadChunkSize *= 1024;
|
2013-12-20 19:25:49 +00:00
|
|
|
totalPartsCount = (int)Math.ceil((float)totalFileSize / (float)uploadChunkSize);
|
2013-10-26 22:34:39 +00:00
|
|
|
readBuffer = new byte[uploadChunkSize];
|
2013-10-25 15:19:00 +00:00
|
|
|
}
|
2013-12-20 19:25:49 +00:00
|
|
|
|
2013-10-25 15:19:00 +00:00
|
|
|
int readed = stream.read(readBuffer);
|
|
|
|
int toAdd = 0;
|
|
|
|
if (key != null && readed % 16 != 0) {
|
|
|
|
toAdd += 16 - readed % 16;
|
|
|
|
}
|
|
|
|
byte[] sendBuffer = new byte[readed + toAdd];
|
|
|
|
if (readed != uploadChunkSize) {
|
|
|
|
isLastPart = true;
|
|
|
|
}
|
|
|
|
System.arraycopy(readBuffer, 0, sendBuffer, 0, readed);
|
|
|
|
if (key != null) {
|
2014-02-28 22:28:25 +00:00
|
|
|
sendBuffer = Utilities.aesIgeEncryption(sendBuffer, key, iv, true, true, 0);
|
2013-10-25 15:19:00 +00:00
|
|
|
}
|
|
|
|
mdEnc.update(sendBuffer, 0, readed + toAdd);
|
2013-12-20 19:25:49 +00:00
|
|
|
if (isBigFile) {
|
|
|
|
TLRPC.TL_upload_saveBigFilePart req = new TLRPC.TL_upload_saveBigFilePart();
|
|
|
|
req.file_part = currentPartNum;
|
|
|
|
req.file_id = currentFileId;
|
|
|
|
req.file_total_parts = totalPartsCount;
|
|
|
|
req.bytes = sendBuffer;
|
|
|
|
finalRequest = req;
|
|
|
|
} else {
|
|
|
|
TLRPC.TL_upload_saveFilePart req = new TLRPC.TL_upload_saveFilePart();
|
|
|
|
req.file_part = currentPartNum;
|
|
|
|
req.file_id = currentFileId;
|
|
|
|
req.bytes = sendBuffer;
|
|
|
|
finalRequest = req;
|
|
|
|
}
|
2013-10-25 15:19:00 +00:00
|
|
|
currentUploaded += readed;
|
|
|
|
} catch (Exception e) {
|
2013-12-20 19:25:49 +00:00
|
|
|
FileLog.e("tmessages", e);
|
2013-10-25 15:19:00 +00:00
|
|
|
delegate.didFailedUploadingFile(this);
|
|
|
|
return;
|
|
|
|
}
|
2013-12-20 19:25:49 +00:00
|
|
|
requestToken = ConnectionsManager.Instance.performRpc(finalRequest, new RPCRequest.RPCRequestDelegate() {
|
2013-10-25 15:19:00 +00:00
|
|
|
@Override
|
|
|
|
public void run(TLObject response, TLRPC.TL_error error) {
|
|
|
|
requestToken = 0;
|
|
|
|
if (error == null) {
|
|
|
|
if (response instanceof TLRPC.TL_boolTrue) {
|
|
|
|
currentPartNum++;
|
|
|
|
delegate.didChangedUploadProgress(FileUploadOperation.this, (float)currentUploaded / (float)totalFileSize);
|
|
|
|
if (isLastPart) {
|
|
|
|
state = 3;
|
|
|
|
if (key == null) {
|
2013-12-20 19:25:49 +00:00
|
|
|
TLRPC.InputFile result;
|
|
|
|
if (isBigFile) {
|
|
|
|
result = new TLRPC.TL_inputFileBig();
|
|
|
|
} else {
|
|
|
|
result = new TLRPC.TL_inputFile();
|
|
|
|
result.md5_checksum = String.format(Locale.US, "%32s", new BigInteger(1, mdEnc.digest()).toString(16)).replace(' ', '0');
|
|
|
|
}
|
2013-10-25 15:19:00 +00:00
|
|
|
result.parts = currentPartNum;
|
|
|
|
result.id = currentFileId;
|
|
|
|
result.name = uploadingFilePath.substring(uploadingFilePath.lastIndexOf("/") + 1);
|
|
|
|
delegate.didFinishUploadingFile(FileUploadOperation.this, result, null);
|
|
|
|
} else {
|
2013-12-20 19:25:49 +00:00
|
|
|
TLRPC.InputEncryptedFile result;
|
|
|
|
if (isBigFile) {
|
|
|
|
result = new TLRPC.TL_inputEncryptedFileBigUploaded();
|
|
|
|
} else {
|
|
|
|
result = new TLRPC.TL_inputEncryptedFileUploaded();
|
|
|
|
result.md5_checksum = String.format(Locale.US, "%32s", new BigInteger(1, mdEnc.digest()).toString(16)).replace(' ', '0');
|
|
|
|
}
|
2013-10-25 15:19:00 +00:00
|
|
|
result.parts = currentPartNum;
|
|
|
|
result.id = currentFileId;
|
|
|
|
result.key_fingerprint = fingerprint;
|
|
|
|
delegate.didFinishUploadingFile(FileUploadOperation.this, null, result);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
startUploadRequest();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
delegate.didFailedUploadingFile(FileUploadOperation.this);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
delegate.didFailedUploadingFile(FileUploadOperation.this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, new RPCRequest.RPCProgressDelegate() {
|
|
|
|
@Override
|
|
|
|
public void progress(int length, int progress) {
|
|
|
|
|
|
|
|
}
|
|
|
|
}, null, true, RPCRequest.RPCRequestClassUploadMedia, ConnectionsManager.DEFAULT_DATACENTER_ID);
|
|
|
|
}
|
|
|
|
}
|