1/*
2  Copyright (C) 2000-2005 SKYRIX Software AG
3
4  This file is part of SOPE.
5
6  SOPE is free software; you can redistribute it and/or modify it under
7  the terms of the GNU Lesser General Public License as published by the
8  Free Software Foundation; either version 2, or (at your option) any
9  later version.
10
11  SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12  WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14  License for more details.
15
16  You should have received a copy of the GNU Lesser General Public
17  License along with SOPE; see the file COPYING.  If not, write to the
18  Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19  02111-1307, USA.
20*/
21
22#include "NGMimeJoinedData.h"
23#include "common.h"
24#include "timeMacros.h"
25#include <string.h>
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <fcntl.h>
29#include <unistd.h>
30#include "NGMimeFileData.h"
31
32@implementation NGMimeJoinedData
33
34- (id)init {
35  if ((self = [super init])) {
36    self->joinedDataObjects = [[NSMutableArray alloc] initWithCapacity:16];
37  }
38  return self;
39}
40
41- (void)dealloc {
42  [self->joinedDataObjects release];
43  [super dealloc];
44}
45
46/* NSCopying */
47
48- (id)copyWithZone:(NSZone *)_zone {
49  // TODO: we are mutable, is -retain a bug or feature?
50  return [self retain];
51}
52
53/* data */
54
55- (NSArray *)_joinedDataObjects {
56  return self->joinedDataObjects;
57}
58
59- (NSUInteger)length {
60  NSUInteger i, count, size;
61
62  for (i = 0, count = [self->joinedDataObjects count], size = 0; i < count;i++)
63    size += [[self->joinedDataObjects objectAtIndex:i] length];
64  return size;
65}
66
67/* appending data */
68
69- (void)appendData:(NSData *)_data {
70  if ([_data isKindOfClass:[NGMimeJoinedData class]]) {
71    [self->joinedDataObjects addObjectsFromArray:
72         [(NGMimeJoinedData *)_data _joinedDataObjects]];
73  }
74  else
75    [self->joinedDataObjects addObject:_data];
76}
77
78- (void)appendBytes:(const void *)_bytes length:(unsigned int)_length {
79  NSMutableData *data;
80
81  if (_length == 0)
82    return;
83
84  data = (NSMutableData *)[self->joinedDataObjects lastObject];
85
86  if ([data isKindOfClass:[NSMutableData class]]) {
87    [data appendBytes:_bytes length:_length];
88  }
89  else {
90    /*
91       Note: we create a mutable because it is not unlikely that additional
92             appends are coming.
93    */
94    data = [[NSMutableData alloc] initWithBytes:_bytes length:_length];
95    if (data != nil) [self->joinedDataObjects addObject:data];
96    [data release];
97  }
98}
99
100/* writing to file */
101
102- (BOOL)writeToFile:(NSString*)_path atomically:(BOOL)_useAuxiliaryFile {
103  NSString      *filename = nil;
104  NSEnumerator  *enumerator;
105  NSData        *data;
106  volatile BOOL result;
107
108  int fd;
109
110  filename = _path;
111
112  fd = open([filename fileSystemRepresentation],
113            O_WRONLY | O_CREAT | O_TRUNC, 0600);
114  if (fd == -1) {
115    fprintf(stderr, "Could not open file for writing %s: %s\n",
116            [filename fileSystemRepresentation], strerror(errno));
117    return NO;
118  }
119
120  result     = YES;
121  enumerator = [self->joinedDataObjects objectEnumerator];
122
123  while ((data = [enumerator nextObject])) {
124
125    TIME_START("write bytes ");
126
127    if ([data isKindOfClass:[NGMimeFileData class]]) {
128      if (![(NGMimeFileData *)data appendDataToFileDesc:fd]) {
129        fprintf(stderr,
130#if GS_64BIT_OLD
131                "Failed to write %i bytes to %s: %s\n",
132#else
133                "Failed to write %li bytes to %s: %s\n",
134#endif
135                [data length],
136                [filename fileSystemRepresentation], strerror(errno));
137        close(fd);
138      }
139    }
140    else {
141      const void *bytes;
142      unsigned   len;
143
144      TIME_START("bytes ...")
145        bytes  = [data bytes];
146        len    = [data length];
147      TIME_END;
148
149      if (write(fd, bytes, len) != (int)len) {
150        fprintf(stderr, "Failed to write %i bytes to %s: %s\n",
151                len, [filename fileSystemRepresentation], strerror(errno));
152        close(fd);
153        return NO;
154      }
155    }
156    TIME_END;
157  }
158  close(fd);
159
160  return result;
161}
162
163/* description */
164
165- (NSString *)description {
166  NSMutableString *ms;
167
168  ms = [NSMutableString stringWithCapacity:128];
169  [ms appendFormat:@"<0x%p[%@]:", self, NSStringFromClass([self class])];
170  [ms appendFormat:@" joinedDataObjects=%d>",
171        (int)[self->joinedDataObjects count]];
172  [ms appendString:@">"];
173  return ms;
174}
175
176@end /* NGMimeJoinedData */
177