mirror of
https://github.com/danog/Telegram.git
synced 2024-12-04 10:27:46 +01:00
344 lines
12 KiB
Objective-C
344 lines
12 KiB
Objective-C
/*
|
|
* This is the source code of Telegram for iOS v. 1.1
|
|
* 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 Peter Iakovlev, 2013.
|
|
*/
|
|
|
|
#import "TGDocumentMediaAttachment.h"
|
|
|
|
#import "PSCoding.h"
|
|
#import "PSKeyValueEncoder.h"
|
|
#import "PSKeyValueDecoder.h"
|
|
|
|
#import "TGMessage.h"
|
|
|
|
@interface TGDocumentMediaAttachment () {
|
|
NSArray *_textCheckingResults;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation TGDocumentMediaAttachment
|
|
|
|
- (id)init
|
|
{
|
|
self = [super init];
|
|
if (self != nil)
|
|
{
|
|
self.type = TGDocumentMediaAttachmentType;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (instancetype)copyWithZone:(NSZone *)__unused zone {
|
|
TGDocumentMediaAttachment *document = [[TGDocumentMediaAttachment alloc] init];
|
|
|
|
document->_documentId = _documentId;
|
|
document->_localDocumentId = _localDocumentId;
|
|
document->_accessHash = _accessHash;
|
|
document->_datacenterId = _datacenterId;
|
|
document->_userId = _userId;
|
|
document->_date = _date;
|
|
document->_mimeType = _mimeType;
|
|
document->_size = _size;
|
|
document->_thumbnailInfo = _thumbnailInfo;
|
|
document->_documentUri = _documentUri;
|
|
document->_attributes = _attributes;
|
|
document->_caption = _caption;
|
|
document->_textCheckingResults = _textCheckingResults;
|
|
|
|
return document;
|
|
}
|
|
|
|
- (instancetype)initWithCoder:(NSCoder *)aDecoder
|
|
{
|
|
self = [super init];
|
|
if (self != nil)
|
|
{
|
|
self.type = TGDocumentMediaAttachmentType;
|
|
|
|
_documentId = [aDecoder decodeInt64ForKey:@"documentId"];
|
|
_localDocumentId = [aDecoder decodeInt64ForKey:@"localDocumentId"];
|
|
_accessHash = [aDecoder decodeInt64ForKey:@"accessHash"];
|
|
_datacenterId = [aDecoder decodeInt32ForKey:@"datacenterId"];
|
|
_userId = [aDecoder decodeInt32ForKey:@"userId"];
|
|
_date = [aDecoder decodeInt32ForKey:@"date"];
|
|
_mimeType = [aDecoder decodeObjectForKey:@"mimeType"];
|
|
_size = [aDecoder decodeInt32ForKey:@"size"];
|
|
_thumbnailInfo = [aDecoder decodeObjectForKey:@"thumbnailInfo"];
|
|
_documentUri = [aDecoder decodeObjectForKey:@"documentUri"];
|
|
_attributes = [aDecoder decodeObjectForKey:@"attributes"];
|
|
_caption = [aDecoder decodeObjectForKey:@"caption"];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)encodeWithCoder:(NSCoder *)aCoder
|
|
{
|
|
[aCoder encodeInt64:_documentId forKey:@"documentId"];
|
|
[aCoder encodeInt64:_localDocumentId forKey:@"localDocumentId"];
|
|
[aCoder encodeInt64:_accessHash forKey:@"accessHash"];
|
|
[aCoder encodeInt32:_datacenterId forKey:@"datacenterId"];
|
|
[aCoder encodeInt32:_userId forKey:@"userId"];
|
|
[aCoder encodeInt32:_date forKey:@"date"];
|
|
if (_mimeType != nil)
|
|
[aCoder encodeObject:_mimeType forKey:@"mimeType"];
|
|
[aCoder encodeInt32:_size forKey:@"size"];
|
|
if (_thumbnailInfo != nil)
|
|
[aCoder encodeObject:_thumbnailInfo forKey:@"thumbnailInfo"];
|
|
if (_documentUri != nil)
|
|
[aCoder encodeObject:_documentUri forKey:@"documentUri"];
|
|
if (_attributes != nil)
|
|
[aCoder encodeObject:_attributes forKey:@"attributes"];
|
|
if (_caption != nil) {
|
|
[aCoder encodeObject:_caption forKey:@"caption"];
|
|
}
|
|
}
|
|
|
|
- (BOOL)isEqual:(id)object
|
|
{
|
|
if (object == self)
|
|
return true;
|
|
|
|
if (![object isKindOfClass:[TGDocumentMediaAttachment class]])
|
|
return false;
|
|
|
|
TGDocumentMediaAttachment *other = object;
|
|
if (_documentId == other->_documentId && _localDocumentId == other->_localDocumentId && _accessHash == other->_accessHash && _datacenterId == other->_datacenterId && _userId == other->_userId && _date == other->_date && TGObjectCompare(_mimeType, other->_mimeType) && _size == other->_size && TGObjectCompare(_thumbnailInfo, other->_thumbnailInfo) && TGObjectCompare(_documentUri, other->_documentUri) && TGObjectCompare(_attributes, other->_attributes) && TGStringCompare(_caption, other->_caption))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
- (void)serialize:(NSMutableData *)data
|
|
{
|
|
int dataLengthPtr = (int)data.length;
|
|
int zero = 0;
|
|
[data appendBytes:&zero length:4];
|
|
|
|
uint8_t version = 5;
|
|
[data appendBytes:&version length:sizeof(version)];
|
|
|
|
[data appendBytes:&_localDocumentId length:sizeof(_localDocumentId)];
|
|
|
|
[data appendBytes:&_documentId length:sizeof(_documentId)];
|
|
[data appendBytes:&_accessHash length:sizeof(_accessHash)];
|
|
[data appendBytes:&_datacenterId length:sizeof(_datacenterId)];
|
|
[data appendBytes:&_userId length:sizeof(_userId)];
|
|
[data appendBytes:&_date length:sizeof(_date)];
|
|
|
|
NSData *filenameData = [[self fileName] dataUsingEncoding:NSUTF8StringEncoding];
|
|
int filenameLength = (int)filenameData.length;
|
|
[data appendBytes:&filenameLength length:sizeof(filenameLength)];
|
|
[data appendData:filenameData];
|
|
|
|
NSData *mimeData = [_mimeType dataUsingEncoding:NSUTF8StringEncoding];
|
|
int mimeLength = (int)mimeData.length;
|
|
[data appendBytes:&mimeLength length:sizeof(mimeLength)];
|
|
[data appendData:mimeData];
|
|
|
|
[data appendBytes:&_size length:sizeof(_size)];
|
|
|
|
uint8_t thumbnailExists = _thumbnailInfo != nil;
|
|
[data appendBytes:&thumbnailExists length:sizeof(thumbnailExists)];
|
|
[_thumbnailInfo serialize:data];
|
|
|
|
NSData *uriData = [_documentUri dataUsingEncoding:NSUTF8StringEncoding];
|
|
int uriLength = (int)uriData.length;
|
|
[data appendBytes:&uriLength length:sizeof(uriLength)];
|
|
if (uriData != nil)
|
|
[data appendData:uriData];
|
|
|
|
PSKeyValueEncoder *encoder = [[PSKeyValueEncoder alloc] init];
|
|
[encoder encodeArray:_attributes forCKey:"attributes"];
|
|
int32_t attributesLength = (int32_t)encoder.data.length;
|
|
[data appendBytes:&attributesLength length:4];
|
|
[data appendData:encoder.data];
|
|
|
|
NSData *captionData = [_caption dataUsingEncoding:NSUTF8StringEncoding];
|
|
int32_t captionLength = (int)captionData.length;
|
|
[data appendBytes:&captionLength length:sizeof(captionLength)];
|
|
if (captionData != nil) {
|
|
[data appendData:captionData];
|
|
}
|
|
|
|
int dataLength = (int)(data.length - dataLengthPtr - 4);
|
|
[data replaceBytesInRange:NSMakeRange(dataLengthPtr, 4) withBytes:&dataLength];
|
|
}
|
|
|
|
- (TGMediaAttachment *)parseMediaAttachment:(NSInputStream *)is
|
|
{
|
|
int dataLength = 0;
|
|
[is read:(uint8_t *)&dataLength maxLength:4];
|
|
|
|
uint8_t version = 0;
|
|
[is read:&version maxLength:sizeof(version)];
|
|
if (version != 1 && version != 2 && version != 3 && version != 4 && version != 5)
|
|
{
|
|
TGLog(@"***** Document serialized version mismatch");
|
|
return nil;
|
|
}
|
|
|
|
TGDocumentMediaAttachment *documentAttachment = [[TGDocumentMediaAttachment alloc] init];
|
|
|
|
if (version >= 2)
|
|
[is read:(uint8_t *)&documentAttachment->_localDocumentId maxLength:sizeof(documentAttachment->_localDocumentId)];
|
|
|
|
[is read:(uint8_t *)&documentAttachment->_documentId maxLength:sizeof(documentAttachment->_documentId)];
|
|
[is read:(uint8_t *)&documentAttachment->_accessHash maxLength:sizeof(documentAttachment->_accessHash)];
|
|
[is read:(uint8_t *)&documentAttachment->_datacenterId maxLength:sizeof(documentAttachment->_datacenterId)];
|
|
[is read:(uint8_t *)&documentAttachment->_userId maxLength:sizeof(documentAttachment->_userId)];
|
|
[is read:(uint8_t *)&documentAttachment->_date maxLength:sizeof(documentAttachment->_date)];
|
|
|
|
NSString *legacyFileName = @"file";
|
|
int filenameLength = 0;
|
|
[is read:(uint8_t *)&filenameLength maxLength:sizeof(filenameLength)];
|
|
if (filenameLength != 0)
|
|
{
|
|
uint8_t *filenameBytes = malloc(filenameLength);
|
|
[is read:filenameBytes maxLength:filenameLength];
|
|
legacyFileName = [[NSString alloc] initWithBytesNoCopy:filenameBytes length:filenameLength encoding:NSUTF8StringEncoding freeWhenDone:true];
|
|
}
|
|
|
|
int mimeLength = 0;
|
|
[is read:(uint8_t *)&mimeLength maxLength:sizeof(mimeLength)];
|
|
if (mimeLength != 0)
|
|
{
|
|
uint8_t *mimeBytes = malloc(mimeLength);
|
|
[is read:mimeBytes maxLength:mimeLength];
|
|
documentAttachment.mimeType = [[NSString alloc] initWithBytesNoCopy:mimeBytes length:mimeLength encoding:NSUTF8StringEncoding freeWhenDone:true];
|
|
}
|
|
|
|
[is read:(uint8_t *)&documentAttachment->_size maxLength:sizeof(documentAttachment->_size)];
|
|
|
|
uint8_t thumbnailExists = 0;
|
|
[is read:&thumbnailExists maxLength:sizeof(thumbnailExists)];
|
|
if (thumbnailExists)
|
|
{
|
|
documentAttachment.thumbnailInfo = [TGImageInfo deserialize:is];
|
|
}
|
|
|
|
if (version >= 3)
|
|
{
|
|
int uriLength = 0;
|
|
[is read:(uint8_t *)&uriLength maxLength:sizeof(uriLength)];
|
|
if (uriLength > 0)
|
|
{
|
|
uint8_t *uriBytes = malloc(uriLength);
|
|
[is read:uriBytes maxLength:uriLength];
|
|
documentAttachment.documentUri = [[NSString alloc] initWithBytesNoCopy:uriBytes length:uriLength encoding:NSUTF8StringEncoding freeWhenDone:true];
|
|
}
|
|
}
|
|
|
|
if (version >= 4)
|
|
{
|
|
int32_t attributesSize = 0;
|
|
[is read:(uint8_t *)&attributesSize maxLength:4];
|
|
if (attributesSize > 0)
|
|
{
|
|
uint8_t *attributeBytes = malloc(attributesSize);
|
|
[is read:attributeBytes maxLength:attributesSize];
|
|
NSData *data = [[NSData alloc] initWithBytesNoCopy:attributeBytes length:attributesSize freeWhenDone:true];
|
|
PSKeyValueDecoder *decoder = [[PSKeyValueDecoder alloc] initWithData:data];
|
|
documentAttachment.attributes = [decoder decodeArrayForCKey:"attributes"];
|
|
}
|
|
}
|
|
|
|
if (version >= 5) {
|
|
int32_t captionLength = 0;
|
|
[is read:(uint8_t *)&captionLength maxLength:sizeof(captionLength)];
|
|
if (captionLength > 0)
|
|
{
|
|
uint8_t *captionBytes = malloc(captionLength);
|
|
[is read:captionBytes maxLength:captionLength];
|
|
documentAttachment.caption = [[NSString alloc] initWithBytesNoCopy:captionBytes length:captionLength encoding:NSUTF8StringEncoding freeWhenDone:true];
|
|
}
|
|
}
|
|
|
|
bool hasFilenameAttribute = false;
|
|
for (id attribute in documentAttachment.attributes)
|
|
{
|
|
if ([attribute isKindOfClass:[TGDocumentAttributeFilename class]])
|
|
{
|
|
hasFilenameAttribute = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!hasFilenameAttribute)
|
|
{
|
|
NSMutableArray *array = [[NSMutableArray alloc] initWithArray:documentAttachment.attributes];
|
|
[array addObject:[[TGDocumentAttributeFilename alloc] initWithFilename:legacyFileName]];
|
|
documentAttachment.attributes = array;
|
|
}
|
|
|
|
return documentAttachment;
|
|
}
|
|
|
|
- (NSString *)fileName
|
|
{
|
|
NSString *fileName = @"file";
|
|
for (id attribute in _attributes)
|
|
{
|
|
if ([attribute isKindOfClass:[TGDocumentAttributeFilename class]])
|
|
{
|
|
fileName = ((TGDocumentAttributeFilename *)attribute).filename;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return fileName;
|
|
}
|
|
|
|
- (NSString *)safeFileName
|
|
{
|
|
return [TGDocumentMediaAttachment safeFileNameForFileName:[self fileName]];
|
|
}
|
|
|
|
+ (NSString *)safeFileNameForFileName:(NSString *)fileName
|
|
{
|
|
if (fileName.length == 0)
|
|
return @"file";
|
|
|
|
return [fileName stringByReplacingOccurrencesOfString:@"/" withString:@"_"];
|
|
}
|
|
|
|
- (bool)isAnimated {
|
|
for (id attribute in _attributes) {
|
|
if ([attribute isKindOfClass:[TGDocumentAttributeAnimated class]]) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
- (CGSize)pictureSize {
|
|
for (id attribute in _attributes) {
|
|
if ([attribute isKindOfClass:[TGDocumentAttributeImageSize class]]) {
|
|
return ((TGDocumentAttributeImageSize *)attribute).size;
|
|
} else if ([attribute isKindOfClass:[TGDocumentAttributeVideo class]]) {
|
|
return ((TGDocumentAttributeVideo *)attribute).size;
|
|
}
|
|
}
|
|
|
|
return CGSizeZero;
|
|
}
|
|
|
|
- (NSArray *)textCheckingResults
|
|
{
|
|
if (_caption.length < 2)
|
|
_textCheckingResults = [NSArray array];
|
|
|
|
if (_textCheckingResults == nil)
|
|
{
|
|
NSArray *textCheckingResults = [TGMessage textCheckingResultsForText:_caption highlightMentionsAndTags:true highlightCommands:true];
|
|
_textCheckingResults = textCheckingResults ?: [NSArray array];
|
|
}
|
|
|
|
return _textCheckingResults;
|
|
}
|
|
|
|
@end
|