Support for explicitly designating an object to be exposed as a structure

on D-Bus. This is only required in some corner cases where the structure
appears inside a variant-typed argument. This means that we don't have any
introspection information to decide whether we want to marshall an NSArray
as a D-Bus structure or a D-Bus array.
Also start support for converting NSData to D-Bus byte arrays. 


git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/dbuskit/trunk@37531 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Niels Grewe 2014-01-01 19:36:36 +00:00
parent b15241515a
commit 12639b9de3
6 changed files with 311 additions and 32 deletions

View File

@ -1,3 +1,17 @@
2014-01-01 Niels Grewe <niels.grewe@halbordnung.de>
* Headers/DKStruct.h
* Headers/DBusKit.h
* Source/DKStruct.m:
Helper class for structure-like arrays. This is needed
only for variant typed arguments because these don't
carry the introspection information that lets us decide
whether something is an array or a D-Bus structure
* Source/DKArgument.m:
Support explicit structure typed arguments and start
working on support for converting from NSData to D-Bus
byte arrays.
2013-12-30 Niels Grewe <niels.grewe@halbordnung.de>
* Source/DKMethod.m

View File

@ -24,3 +24,4 @@
#import <DBusKit/DKPort.h>
#import <DBusKit/DKProxy.h>
#import <DBusKit/NSConnection+DBus.h>
#import <DBusKit/DKStruct.h>

52
Headers/DKStruct.h Normal file
View File

@ -0,0 +1,52 @@
/** Interface for collection classes that are boxed as D-Bus structures
Copyright (C) 2014 Free Software Foundation, Inc.
Written by: Niels Grewe <niels.grewe@halbordnung.de>
Created: January 2014
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 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
Library 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 02111 USA.
*/
#import <Foundation/NSArray.h>
/**
* The DKStruct protocol should be adopted by all collection classes
* that are required to be converted to D-Bus structures. A default
* implementation is provided for NSArray, which just returns NO.
* The object also needs to implement -objectEnumerator.
*/
@protocol DKStruct
/**
* Return YES from this method if the D-Bus representation of the
* receiver should be a struct instead of an array.
*/
- (BOOL)isDBusStruct;
@end
@interface NSArray (DBusKit) <DKStruct>
@end
@interface DKStructArray : NSArray
{
NSArray *backingStore;
}
@end
@interface DKMutableStructArray : NSMutableArray
{
NSMutableArray *backingStore;
}
@end

View File

@ -23,6 +23,7 @@
*/
#import <Foundation/NSArray.h>
#import <Foundation/NSData.h>
#import <Foundation/NSDebug.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSException.h>
@ -48,6 +49,8 @@
#import "DKArgument.h"
#import "DKBoxingUtils.h"
#import "DBusKit/DKStruct.h"
#define INCLUDE_RUNTIME_H
#include "config.h"
#undef INCLUDE_RUNTIME_H
@ -1660,31 +1663,54 @@ DKDBusTypeForUnboxingObject(id object)
{
object = [NSArray array];
}
NSAssert1([object respondsToSelector: @selector(objectEnumerator)],
@"Cannot enumerate contents of %@ when creating D-Bus array.",
object);
if (DBUS_TYPE_BYTE != [theChild DBusType])
{
NSAssert1([object respondsToSelector: @selector(objectEnumerator)],
@"Cannot enumerate contents of %@ when creating D-Bus array.",
object);
}
else
{
NSAssert1(([object respondsToSelector: @selector(objectEnumerator)] ||
[object isKindOfClass: [NSData class]]),
@"Cannot enumerate contents of %@ when creating D-Bus array.",
object
);
}
DK_ITER_OPEN_CONTAINER(iter, DBUS_TYPE_ARRAY, [[theChild DBusTypeSignature] UTF8String], &subIter);
elementEnum = [object objectEnumerator];
NS_DURING
{
while (nil != (element = [elementEnum nextObject]))
{
[theChild marshallObject: element
intoIterator: &subIter];
if ([object respondsToSelector: @selector(objectEnumerator)])
{
elementEnum = [object objectEnumerator];
while (nil != (element = [elementEnum nextObject]))
{
[theChild marshallObject: element
intoIterator: &subIter];
}
}
else if ([object isKindOfClass: [NSData class]])
{
NSUInteger len = [object length];
const void *bytes = [object bytes];
NSUInteger pos = 0;
for (pos = 0; pos < len; pos++)
{
DK_ITER_APPEND(&subIter, DBUS_TYPE_BYTE, bytes++);
}
}
}
}
NS_HANDLER
{
// We are already screwed and don't care whether
// dbus_message_iter_close_container() returns OOM.
dbus_message_iter_close_container(iter, &subIter);
[localException raise];
}
{
// We are already screwed and don't care whether
// dbus_message_iter_close_container() returns OOM.
dbus_message_iter_close_container(iter, &subIter);
[localException raise];
}
NS_ENDHANDLER
DK_ITER_CLOSE_CONTAINER(iter, &subIter);
}
@end
@ -1833,7 +1859,7 @@ DKDBusTypeForUnboxingObject(id object)
@implementation DKStructTypeArgument
-(id) unmarshalledObjectFromIterator: (DBusMessageIter*)iter
{
NSMutableArray *theArray = [NSMutableArray new];
DKMutableStructArray *theArray = [DKMutableStructArray new];
NSArray *returnArray = nil;
NSNull *theNull = [NSNull null];
NSUInteger index = 0;
@ -1916,34 +1942,54 @@ DKDBusTypeForUnboxingObject(id object)
* keys/values. This can only be a proper signature if all elements are of the
* same type. Otherwise, the variant type will be returned.
*/
- (NSString*)validSubSignatureOrVariantForEnumerator: (NSEnumerator*)theEnum
- (NSString*)subSignatureForEnumerator: (NSEnumerator*)theEnum
forStruct: (BOOL)isStruct
{
id element = [theEnum nextObject];
NSString *thisSig = [[self DKArgumentWithObject: element] DBusTypeSignature];
NSString *nextSig = thisSig;
NSMutableString *allTypes = [NSMutableString stringWithString: thisSig];
// For homogenous collection, we can get the proper signature, for non-homogenous
// ones, we need to pass down the variant type.
// ones, we need to pass down the variant type if it's not a signature for a struct.
BOOL isHomogenous = YES;
if (nil == element)
{
thisSig = @"v";
}
while ((nil != (element = [theEnum nextObject]))
&& (YES == isHomogenous))
{
thisSig = nextSig;
nextSig = [[self DKArgumentWithObject: element] DBusTypeSignature];
isHomogenous = [thisSig isEqualToString: nextSig];
[allTypes appendString: nextSig];
if (isStruct == NO)
{
isHomogenous = [thisSig isEqualToString: nextSig];
}
}
if (isHomogenous)
{
return thisSig;
}
else
{
return @"v";
}
if (NO == isStruct)
{
if (isHomogenous)
{
return thisSig;
}
else
{
return @"v";
}
}
else
{
return allTypes;
}
}
- (NSString*)validSubSignatureOrVariantForEnumerator: (NSEnumerator*)theEnum
{
return [self subSignatureForEnumerator: theEnum forStruct: NO];
}
- (DKArgument*) DKArgumentWithObject: (id)object
{
if (([object respondsToSelector: @selector(keyEnumerator)])
@ -1972,8 +2018,19 @@ DKDBusTypeForUnboxingObject(id object)
else if ([object respondsToSelector: @selector(objectEnumerator)])
{
NSEnumerator *theEnum = [object objectEnumerator];
NSString *subSig = [self validSubSignatureOrVariantForEnumerator: theEnum];
return [[[DKArgument alloc] initWithDBusSignature: [[@"a" stringByAppendingString: subSig] UTF8String]
NSString *signature = nil;
if ([object respondsToSelector: @selector(isDBusStruct)]
&& [object isDBusStruct])
{
NSString *subSig = [self subSignatureForEnumerator: theEnum forStruct: YES];
signature = [NSString stringWithFormat: @"(%@)", subSig];
}
else
{
NSString *subSig = [self validSubSignatureOrVariantForEnumerator: theEnum];
signature = [NSString stringWithFormat: @"a%@", subSig];
}
return [[[DKArgument alloc] initWithDBusSignature: [signature UTF8String]
name: nil
parent: self] autorelease];
}
@ -1987,6 +2044,13 @@ DKDBusTypeForUnboxingObject(id object)
parent: self] autorelease];
}
}
else if ([object isKindOfClass: [NSData class]])
{
return [[[DKArgument alloc] initWithDBusSignature: "ay"
name: nil
parent: self] autorelease];
}
else
{
// Simple types are quite straightforward, if we can find an appropriate

146
Source/DKStruct.m Normal file
View File

@ -0,0 +1,146 @@
/** Categories on NSArray so that it's boxed as D-Bus structures
Copyright (C) 2014 Free Software Foundation, Inc.
Written by: Niels Grewe <niels.grewe@halbordnung.de>
Created: January 2014
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 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
Library 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 02111 USA.
*/
#import "DBusKit/DKStruct.h"
@implementation NSArray (DBusKit)
- (BOOL)isDBusStruct
{
return NO;
}
@end
@implementation DKStructArray
- (BOOL)isDBusStruct
{
return YES;
}
- (id) initWithObjects: (const id[])objects count: (NSUInteger)count
{
// Special case, class cluster: No super init
backingStore = [[NSArray alloc] initWithObjects: objects count: count];
if (nil == backingStore)
{
DESTROY(self);
return nil;
}
return self;
}
- (NSUInteger)count
{
return [backingStore count];
}
- (id)objectAtIndex: (NSUInteger)index
{
return [backingStore objectAtIndex: index];
}
- (void)dealloc
{
DESTROY(backingStore);
[super dealloc];
}
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state
objects:(id *)stackbuf
count:(NSUInteger)len
{
return [backingStore countByEnumeratingWithState: state
objects: stackbuf
count: len];
}
@end
@implementation DKMutableStructArray
- (BOOL)isDBusStruct
{
return YES;
}
- (id) initWithCapacity: (NSUInteger)count
{
// Special case, class cluster: No super init
backingStore = [[NSMutableArray alloc] initWithCapacity: count];
if (nil == backingStore)
{
DESTROY(self);
return nil;
}
return self;
}
- (NSUInteger)count
{
return [backingStore count];
}
- (id)objectAtIndex: (NSUInteger)index
{
return [backingStore objectAtIndex: index];
}
- (void)dealloc
{
DESTROY(backingStore);
[super dealloc];
}
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state
objects:(id *)stackbuf
count:(NSUInteger)len
{
return [backingStore countByEnumeratingWithState: state
objects: stackbuf
count: len];
}
- (void)insertObject: (id)obj atIndex: (NSUInteger)idx
{
[backingStore insertObject: obj atIndex: idx];
}
- (void)removeObjectAtIndex: (NSUInteger)idx
{
[backingStore removeObjectAtIndex: idx];
}
- (void)addObject: (id)obj
{
[backingStore addObject: obj];
}
- (void)removeLastObject
{
[backingStore removeLastObject];
}
- (void)replaceObjectAtIndex: (NSUInteger)idx withObject: (id)obj
{
[backingStore replaceObjectAtIndex: idx withObject: obj];
}
@end

View File

@ -19,6 +19,7 @@ DBusKit_HEADER_FILES = \
DKPort.h \
DKPortNameServer.h \
DKProxy.h \
DKStruct.h \
NSConnection+DBus.h
#
# Class files
@ -45,6 +46,7 @@ DBusKit_OBJC_FILES = \
DKPropertyMethod.m \
DKProxy.m \
DKSignal.m \
DKStruct.m \
NSConnection+DBus.m