Fixed a double release in a garbage collected environment.
5 // Created by Jens Alfke on 5/10/08.
6 // Copyright 2008 Jens Alfke. All rights reserved.
9 #import "BLIPMessage.h"
10 #import "BLIP_Internal.h"
11 #import "BLIPReader.h"
12 #import "BLIPWriter.h"
16 #import "ExceptionUtils.h"
19 // From Google Toolbox For Mac <http://code.google.com/p/google-toolbox-for-mac/>
20 #import "GTMNSData+zlib.h"
23 @implementation BLIPMessage
26 - (id) _initWithConnection: (BLIPConnection*)connection
28 flags: (BLIPMessageFlags)flags
34 _connection = [connection retain];
40 _properties = [[BLIPMutableProperties alloc] init];
41 _propertiesAvailable = YES;
43 _encodedBody = body.mutableCopy;
45 LogTo(BLIPVerbose,@"INIT %@",self);
52 LogTo(BLIPVerbose,@"DEALLOC %@",self);
53 [_properties release];
54 [_encodedBody release];
55 [_mutableBody release];
57 [_connection release];
62 - (NSString*) description
64 NSUInteger length = (_body.length ?: _mutableBody.length) ?: _encodedBody.length;
65 NSMutableString *desc = [NSMutableString stringWithFormat: @"%@[#%u, %u bytes",
66 self.class,_number, length];
67 if( _flags & kBLIP_Compressed ) {
68 if( _encodedBody && _encodedBody.length != length )
69 [desc appendFormat: @" (%u gzipped)", _encodedBody.length];
71 [desc appendString: @", gzipped"];
73 if( _flags & kBLIP_Urgent )
74 [desc appendString: @", urgent"];
75 if( _flags & kBLIP_NoReply )
76 [desc appendString: @", noreply"];
77 if( _flags & kBLIP_Meta )
78 [desc appendString: @", META"];
79 [desc appendString: @"]"];
83 - (NSString*) descriptionWithProperties
85 NSMutableString *desc = (NSMutableString*)self.description;
86 [desc appendFormat: @" %@", self.properties.allProperties];
92 #pragma mark PROPERTIES & METADATA:
95 @synthesize connection=_connection, number=_number, isMine=_isMine, isMutable=_isMutable,
96 _bytesWritten, sent=_sent, propertiesAvailable=_propertiesAvailable, complete=_complete,
97 representedObject=_representedObject;
100 - (void) _setFlag: (BLIPMessageFlags)flag value: (BOOL)value
102 Assert(_isMine && _isMutable);
109 - (BLIPMessageFlags) _flags {return _flags;}
111 - (BOOL) compressed {return (_flags & kBLIP_Compressed) != 0;}
112 - (BOOL) urgent {return (_flags & kBLIP_Urgent) != 0;}
113 - (void) setCompressed: (BOOL)compressed {[self _setFlag: kBLIP_Compressed value: compressed];}
114 - (void) setUrgent: (BOOL)high {[self _setFlag: kBLIP_Urgent value: high];}
119 if( ! _body && _isMine )
120 return [[_mutableBody copy] autorelease];
125 - (void) setBody: (NSData*)body
127 Assert(_isMine && _isMutable);
129 [_mutableBody setData: body];
131 _mutableBody = [body mutableCopy];
134 - (void) _addToBody: (NSData*)data
138 [_mutableBody appendData: data];
140 _mutableBody = [data mutableCopy];
145 - (void) addToBody: (NSData*)data
147 Assert(_isMine && _isMutable);
148 [self _addToBody: data];
152 - (NSString*) bodyString
154 NSData *body = self.body;
156 return [[[NSString alloc] initWithData: body encoding: NSUTF8StringEncoding] autorelease];
161 - (void) setBodyString: (NSString*)string
163 self.body = [string dataUsingEncoding: NSUTF8StringEncoding];
164 self.contentType = @"text/plain; charset=UTF-8";
168 - (BLIPProperties*) properties
173 - (BLIPMutableProperties*) mutableProperties
175 Assert(_isMine && _isMutable);
176 return (BLIPMutableProperties*)_properties;
179 - (NSString*) valueOfProperty: (NSString*)property
181 return [_properties valueOfProperty: property];
184 - (void) setValue: (NSString*)value ofProperty: (NSString*)property
186 [self.mutableProperties setValue: value ofProperty: property];
189 - (NSString*) contentType {return [_properties valueOfProperty: @"Content-Type"];}
190 - (void) setContentType: (NSString*)t {[self setValue: t ofProperty: @"Content-Type"];}
191 - (NSString*) profile {return [_properties valueOfProperty: @"Profile"];}
192 - (void) setProfile: (NSString*)p {[self setValue: p ofProperty: @"Profile"];}
201 Assert(_isMine && _isMutable);
204 BLIPProperties *oldProps = _properties;
205 _properties = [oldProps copy];
208 _encodedBody = [_properties.encodedData mutableCopy];
209 Assert(_encodedBody.length>=2);
211 NSData *body = _body ?: _mutableBody;
212 NSUInteger length = body.length;
214 if( self.compressed ) {
215 body = [NSData gtm_dataByGzippingData: body compressionLevel: 5];
216 LogTo(BLIPVerbose,@"Compressed %@ to %u bytes (%.0f%%)", self,body.length,
217 body.length*100.0/length);
219 [_encodedBody appendData: body];
224 - (void) _assignedNumber: (UInt32)number
226 Assert(_number==0,@"%@ has already been sent",self);
232 - (BOOL) _writeFrameTo: (BLIPWriter*)writer maxSize: (UInt16)maxSize
236 Assert(_encodedBody);
237 if( _bytesWritten==0 )
238 LogTo(BLIP,@"Now sending %@",self);
239 ssize_t lengthToWrite = _encodedBody.length - _bytesWritten;
240 if( lengthToWrite <= 0 && _bytesWritten > 0 )
242 Assert(maxSize > sizeof(BLIPFrameHeader));
243 maxSize -= sizeof(BLIPFrameHeader);
244 UInt16 flags = _flags;
245 if( lengthToWrite > maxSize ) {
246 lengthToWrite = maxSize;
247 flags |= kBLIP_MoreComing;
248 LogTo(BLIPVerbose,@"%@ pushing frame, bytes %u-%u", self, _bytesWritten, _bytesWritten+lengthToWrite);
250 flags &= ~kBLIP_MoreComing;
251 LogTo(BLIPVerbose,@"%@ pushing frame, bytes %u-%u (finished)", self, _bytesWritten, _bytesWritten+lengthToWrite);
254 // First write the frame header:
255 BLIPFrameHeader header = { NSSwapHostIntToBig(kBLIPFrameHeaderMagicNumber),
256 NSSwapHostIntToBig(_number),
257 NSSwapHostShortToBig(flags),
258 NSSwapHostShortToBig(sizeof(BLIPFrameHeader) + lengthToWrite) };
260 [writer writeData: [NSData dataWithBytes: &header length: sizeof(header)]];
262 // Then write the body:
263 if( lengthToWrite > 0 ) {
264 [writer writeData: [NSData dataWithBytes: (UInt8*)_encodedBody.bytes + _bytesWritten
265 length: lengthToWrite]];
266 _bytesWritten += lengthToWrite;
268 return (flags & kBLIP_MoreComing) != 0;
272 - (BOOL) _receivedFrameWithHeader: (const BLIPFrameHeader*)header body: (NSData*)body
275 AssertEq(header->number,_number);
276 Assert(_flags & kBLIP_MoreComing);
278 BLIPMessageType frameType = (header->flags & kBLIP_TypeMask), curType = (_flags & kBLIP_TypeMask);
279 if( frameType != curType ) {
280 Assert(curType==kBLIP_RPY && frameType==kBLIP_ERR && _mutableBody.length==0,
281 @"Incoming frame's type %i doesn't match %@",frameType,self);
282 _flags = (_flags & ~kBLIP_TypeMask) | frameType;
286 [_encodedBody appendData: body];
288 _encodedBody = [body mutableCopy];
289 LogTo(BLIPVerbose,@"%@ rcvd bytes %u-%u", self, _encodedBody.length-body.length, _encodedBody.length);
291 if( ! _properties ) {
292 // Try to extract the properties:
294 setObj(&_properties, [BLIPProperties propertiesWithEncodedData: _encodedBody usedLength: &usedLength]);
296 [_encodedBody replaceBytesInRange: NSMakeRange(0,usedLength)
297 withBytes: NULL length: 0];
298 } else if( usedLength < 0 )
300 self.propertiesAvailable = YES;
303 if( ! (header->flags & kBLIP_MoreComing) ) {
304 // After last frame, decode the data:
305 _flags &= ~kBLIP_MoreComing;
308 unsigned encodedLength = _encodedBody.length;
309 if( self.compressed && encodedLength>0 ) {
310 _body = [[NSData gtm_dataByInflatingData: _encodedBody] copy];
313 LogTo(BLIPVerbose,@"Uncompressed %@ from %u bytes (%.1fx)", self, encodedLength,
314 _body.length/(float)encodedLength);
316 _body = [_encodedBody copy];
318 setObj(&_encodedBody,nil);
319 self.propertiesAvailable = self.complete = YES;
325 - (void) _connectionClosed
329 _flags |= kBLIP_MoreComing;
338 Copyright (c) 2008, Jens Alfke <jens@mooseyard.com>. All rights reserved.
340 Redistribution and use in source and binary forms, with or without modification, are permitted
341 provided that the following conditions are met:
343 * Redistributions of source code must retain the above copyright notice, this list of conditions
344 and the following disclaimer.
345 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
346 and the following disclaimer in the documentation and/or other materials provided with the
349 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
350 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
351 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
352 BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
353 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
354 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
355 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
356 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.