Skip to content

Instantly share code, notes, and snippets.

@kosugi
Last active December 10, 2015 09:38
Show Gist options
  • Select an option

  • Save kosugi/4415114 to your computer and use it in GitHub Desktop.

Select an option

Save kosugi/4415114 to your computer and use it in GitHub Desktop.
checks missing files (bad “Location” field) in “iTunes Music Library.xml” file.
// -*- mode: objc; coding: utf-8 -*-
#import <Foundation/Foundation.h>
static NSString *nvl(NSString *s1, NSString *s2)
{
return s1? s1: s2;
}
@interface Parser: NSObject <NSXMLParserDelegate>
- (void)parse:(NSURL *)url;
@end
@implementation Parser
{
int _depth; // <dict> のネスト度合い
int _targetDepth;
BOOL _shouldStore;
NSString *_keyName;
NSString *_prevElementName;
NSMutableString *_buf;
NSMutableDictionary *_track;
int _numTracks;
NSMutableArray *_missedTracks;
}
static NSCharacterSet *digitCharSet;
+ (void)initialize
{
digitCharSet = [NSCharacterSet characterSetWithCharactersInString:@"0123456789"];
}
+ (BOOL)isDigit:(NSString *)text
{
NSScanner *scanner = [NSScanner localizedScannerWithString:text];
[scanner setCharactersToBeSkipped:nil];
return [scanner scanCharactersFromSet:digitCharSet intoString:NULL] && [scanner isAtEnd];
}
- (void)parse:(NSURL *)url
{
NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
parser.delegate = self;
[parser parse];
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
{
NSLog(@"Error: %ld, Column: %ld, Line: %ld, Description: %@",
[parseError code],
[parser columnNumber],
[parser lineNumber],
[parseError description]);
}
- (void)parserDidStartDocument:(NSXMLParser *)parser
{
_keyName = nil;
_prevElementName = nil;
_shouldStore = NO;
_depth = 0;
_targetDepth = 0;
_buf = [NSMutableString new];
_track = [NSMutableDictionary new];
_missedTracks = [NSMutableArray new];
}
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
printf("%7d tracks\n", _numTracks);
printf("%7ld missed tracks\n", [_missedTracks count]);
for (NSArray *info in _missedTracks) {
printf(
" %s: %s\n",
[[info objectAtIndex:0] cStringUsingEncoding:NSUTF8StringEncoding],
[[info objectAtIndex:1] cStringUsingEncoding:NSUTF8StringEncoding]);
}
}
- (void)store
{
++_numTracks;
NSString *trackType = [_track objectForKey:@"Track Type"];
if ([trackType isEqualToString:@"Remote"]) {
return; // Remote Track は Location を持たない
}
if ([trackType isEqualToString:@"URL"]) {
return; // URL Track は Location を持つが存在確認を行なわないことにする
}
NSString *trackId = [_track objectForKey:@"Track ID"];
NSString *name = [_track objectForKey:@"Name"];
NSString *location = [_track objectForKey:@"Location"];
NSURL *url = [NSURL URLWithString:location];
NSString *path = url.path;
if (![[NSFileManager defaultManager] isReadableFileAtPath:path]) {
[_missedTracks addObject:@[nvl(trackId, @"<>"), nvl(path, nvl(name, @"[]"))]];
}
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
{
if ([@"dict" isEqualToString:elementName]) {
++_depth;
if ([@"key" isEqualToString:_prevElementName] && [Parser isDigit:_keyName]) {
_targetDepth = _depth;
//NSLog(@"Track ID: %@ parsing...", _keyName);
}
}
_shouldStore = 0 < _depth && _targetDepth == _depth;
[_buf setString:@""];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([@"key" isEqualToString:elementName])
{
_keyName = [_buf copy];
}
else if ([@"dict" isEqualToString:elementName])
{
--_depth;
if (_shouldStore) {
_shouldStore = NO;
_targetDepth = 0;
[self store];
[_track removeAllObjects];
}
}
else if (_shouldStore && [@"key" isEqualToString:_prevElementName])
{
NSString *value = [NSString stringWithString:_buf];
[_track setObject:value forKey:_keyName];
}
_prevElementName = [elementName copy];
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
[_buf appendString:string];
}
@end
void doit(NSString *path)
{
NSDate *startTime = [NSDate date];
[[Parser new] parse:[NSURL fileURLWithPath:path]];
NSLog(@"XML parse time is %lf (sec)", [[NSDate date] timeIntervalSinceDate:startTime]);
}
int main(int argc, char **argv)
{
if (argc != 2)
{
printf("usage: %s: itunes_library.xml\n", argv[0]);
return 1;
}
@autoreleasepool
{
doit([NSString stringWithUTF8String:argv[1]]);
}
return 0;
}
TARGET = main
OBJS = main.o
CC = clang
CFLAGS = -fobjc-arc -O2 -Wall
LDFLAGS = -framework Foundation
.m.o:
$(CC) $(CFLAGS) -c $< -o $*.o
.PHONY: all
all: $(OBJS)
$(CC) $(LDFLAGS) $(CFLAGS) -o $(TARGET) $(OBJS)
.PHONY: clean
clean:
$(RM) $(TARGET) $(OBJS)
@kosugi

kosugi commented Dec 31, 2012

Copy link
Copy Markdown
Author

ううむ, 微妙だ…….

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment