diff --git a/Makefile.in b/Makefile.in index ed4e279..66a02b4 100644 --- a/Makefile.in +++ b/Makefile.in @@ -19,5 +19,5 @@ check: rustcorefoundation-test ./rustcorefoundation-test clean: - rm -f *.o *.a *.so *.dylib *.dll *.dummy + rm -f *.o *.a *.so *.dylib *.dll *.dummy rustcorefoundation-test diff --git a/base.rs b/base.rs index e82c928..4ead07e 100644 --- a/base.rs +++ b/base.rs @@ -9,6 +9,10 @@ pub struct CFRange { length: CFIndex } +fn CFRangeMake(off: CFIndex, len: CFIndex) -> CFRange { + CFRange { location: off, length: len } +} + struct __CFAllocator { private: () } pub type CFAllocatorRef = *__CFAllocator; @@ -138,7 +142,4 @@ extern { /* Base Utilities Reference */ // N.B. Some things missing here. - //fn CFRangeMake } - - \ No newline at end of file diff --git a/string.rs b/string.rs index 4f0b6c1..8b0977d 100644 --- a/string.rs +++ b/string.rs @@ -5,6 +5,8 @@ use base::{ CFAllocatorRef, CFIndex, CFOptionFlags, + CFRange, + CFRangeMake, CFRelease, CFTypeRef, CFTypeID, @@ -234,7 +236,7 @@ pub impl CFString { let string_ref = do str::as_buf(string) |bytes, len| { CFStringCreateWithBytesNoCopy(kCFAllocatorDefault, bytes, - len as CFIndex, + (len-1) as CFIndex, // does NOT want trailing NUL kCFStringEncodingUTF8, false as Boolean, kCFAllocatorNull) @@ -243,6 +245,39 @@ pub impl CFString { } } +pub impl CFString { + pub pure fn char_len() -> uint unsafe { + CFStringGetLength(self.obj) as uint + } +} + +pub impl CFString : ToStr { + pure fn to_str() -> ~str unsafe { + let char_len = self.char_len(); + let range : CFRange = CFRangeMake(0 as CFIndex, char_len as CFIndex); + let encoding = kCFStringEncodingUTF8; + let mut bytes_required: CFIndex = 0 as CFIndex; + // first, ask how big the buffer ought to be. + CFStringGetBytes(self.obj, range, encoding, 0, false as Boolean, + ptr::null(), 0, ptr::to_unsafe_ptr(&bytes_required)); + + let buffer : ~[u8] = vec::from_elem(1+bytes_required as uint, '\x00' as u8); + let mut bytes_used: CFIndex = 0 as CFIndex; + // then, allocate the buffer and actually copy. + let chars_written = CFStringGetBytes(self.obj, range, encoding, 0, false as Boolean, + vec::raw::to_ptr(buffer), buffer.len() as CFIndex, + ptr::to_unsafe_ptr(&bytes_used)) as uint; + + assert chars_written == char_len; + // this is dangerous; we over-allocate and nul-terminate the string (during initialization) + assert bytes_used + 1 == buffer.len() as CFIndex; + // then, reinterpret it as as string. you have been warned! + let casted_str : ~str = cast::transmute(move buffer); + // sanity check. + return move casted_str; + } +} + #[link_args="-framework CoreFoundation"] #[nolink] extern { @@ -293,14 +328,16 @@ extern { /* Accessing Characters */ //fn CFStringCreateExternalRepresentation - //fn CFStringGetBytes + fn CFStringGetBytes(theString: CFStringRef, ++range: CFRange, encoding: CFStringEncoding, + lossByte: u8, isExternalRepresentation: Boolean, + buffer: *u8, maxBufLen: CFIndex, usedBufLen: *CFIndex) -> CFIndex; //fn CFStringGetCharacterAtIndex //fn CFStringGetCharacters //fn CFStringGetCharactersPtr //fn CFStringGetCharacterFromInlineBuffer //fn CFStringGetCString //fn CFStringGetCStringPtr - //fn CFStringGetLength + fn CFStringGetLength(theString: CFStringRef) -> CFIndex; //fn CFStringGetPascalString //fn CFStringGetPascalStringPtr //fn CFStringGetRangeOfComposedCharactersAtIndex @@ -349,3 +386,10 @@ extern { //fn CFStringIsSurrogateLowCharacter } +#[test] +fn string_and_back() { + let original = "The quick brown fox jumped over the slow lazy dog."; + let cfstr = CFString::new_static(original); + let converted = cfstr.to_str(); + assert original == converted; +} \ No newline at end of file