-
Notifications
You must be signed in to change notification settings - Fork 3
/
ID3FrameText.m
165 lines (139 loc) · 5.15 KB
/
ID3FrameText.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
//
// ID3FrameText.m
//
#import "ID3FrameText.h"
#import "ID3Parser.h"
#define ID3_TXTFRAME_ENCODING_SIZE 1
#define ID3_TXTFRAME_ENCODING_ISO 0x00
#define ID3_TXTFRAME_ENCODING_UTF16 0x01
#define ID3_TXTFRAME_ENCODING_UTF16BE 0x02
#define ID3_TXTFRAME_ENCODING_UTF8 0x03
@implementation ID3FrameText
@synthesize textEncoding, textStrings, description;
/*
Function initializes a text frame instance. Returns the initialized frame, or nil on error. If nil, check NSError.
- frameIDString is the 3 or 4 letter frame ID
- description is the string description of the frame ID
- bytes is a pointer to beginning of frame header, can't be null.
- error argument can be ommited, but its not recommended
*/
- (id)initWithID:(NSString *)frameIDString description:(NSString*)aDescription version:(ID3_VERSION)version andBytes:(const void *)bytes error:(NSError **)error
{
self = [super initWithID:frameIDString description:aDescription version:version andBytes:bytes error:error];
if(self){
self.textStrings = [[NSMutableArray alloc] init];
//Get the text encoding of the tag.
char* encodingPtr = (char*)[self.dataForParsing bytes];
if(encodingPtr == NULL){//No data to parse
if(error) *error = [ID3Parser errorForCode:ID3_PARSERDOMAIN_EEMPTY underlyingError:nil recoveryObject:self];
[self release];
return nil;
}
NSData *nullChar;
short nullVal = 0;
switch (*encodingPtr) {
case ID3_TXTFRAME_ENCODING_ISO:
{
self.textEncoding = NSISOLatin1StringEncoding;
nullChar = [NSData dataWithBytes:&nullVal length:1];
break;
}
case ID3_TXTFRAME_ENCODING_UTF16:
{
self.textEncoding = NSUTF16StringEncoding;
nullChar = [NSData dataWithBytes:&nullVal length:2];
break;
}
case ID3_TXTFRAME_ENCODING_UTF16BE:
{
self.textEncoding = NSUTF16BigEndianStringEncoding;
nullChar = [NSData dataWithBytes:&nullVal length:2];
break;
}
case ID3_TXTFRAME_ENCODING_UTF8:
{
self.textEncoding = NSUTF8StringEncoding;
nullChar = [NSData dataWithBytes:&nullVal length:1];
break;
}
default:
{
if(error){
*error = [ID3Parser errorForCode:ID3_PARSERDOMAIN_EENCOD underlyingError:nil recoveryObject:self];
}
[self release];
return nil;
}
}
//Parse the text
NSUInteger length = [self.dataForParsing length];
NSUInteger index = 1;
NSRange dataRange;
NSString *frameString;
NSString *userFrameID;
if(self.majorVersion == ID3_VERSION_2) userFrameID = @"TXX";
else userFrameID = @"TXXX";
while(index < length){
NSRange nullDelimeter = [self.dataForParsing rangeOfData:nullChar options:0 range:NSMakeRange(index, length - index)];
if([self.frameID isEqualToString:userFrameID] && self.description == nil){//TXX(X) frame
if(nullDelimeter.location == NSNotFound){
/*FRAME FORMATTING IS WRONG - expecting at least 1 null delimeter*/
if(error) *error = [ID3Parser errorForCode:ID3_PARSERDOMAIN_EFORMAT underlyingError:nil recoveryObject:self];
[self release];
return nil;
}
//set description string
dataRange = NSMakeRange(index, nullDelimeter.location - index);
frameString = [[NSString alloc] initWithData:[self.dataForParsing subdataWithRange:dataRange]
encoding:self.textEncoding];
index = nullDelimeter.location + nullDelimeter.length;
self.description = frameString;
[frameString release];
continue;
}
if(nullDelimeter.location == NSNotFound){//no more null delimeters
//put remainig data into a string
dataRange = NSMakeRange(index, length - index);
frameString = [[NSString alloc] initWithData:[self.dataForParsing subdataWithRange:dataRange] encoding:self.textEncoding];
[self.textStrings addObject:frameString];
[frameString release];
break;
}
//put data up to current delimeter into a string.
dataRange = NSMakeRange(index, nullDelimeter.location - index);
frameString = [[NSString alloc] initWithData:[self.dataForParsing subdataWithRange:dataRange] encoding:self.textEncoding];
[self.textStrings addObject:frameString];
[frameString release];
index = nullDelimeter.location + nullDelimeter.length;
if(self.majorVersion == ID3_VERSION_2 || self.majorVersion == ID3_VERSION_3) break; //in v3 and older, data beyond null char is ignored
}
}
return self;
}
/*
Function returns a NSDictionary describing the frame
- all frames have keys "frameID" "frameDescription" and "value"
*/
- (NSDictionary*)descriptionOfFrame
{
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
[dictionary setValue:self.frameID forKey:@"frameID"];
[dictionary setValue:self.frameDescription forKey:@"frameDescription"];
[dictionary setValue:self.description forKey:@"description"];
//concatenate strings from array...i guess
NSMutableString *value = [[NSMutableString alloc] init];
for(NSString *string in self.textStrings){
[value appendString:[NSString stringWithFormat:@"%@ ", string]];
}
[dictionary setValue:value forKey:@"value"];
[value release];
return [NSDictionary dictionaryWithDictionary:dictionary];
}
- (void)dealloc
{
[textEncoding release];
[description release];
[textStrings release];
[super dealloc];
}
@end