1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 *   http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20#import "TMemoryBuffer.h"
21#import "TTransportError.h"
22
23
24#define GARBAGE_BUFFER_SIZE 4096 // 4KiB
25
26
27@interface TMemoryBuffer ()
28
29@property(strong, nonatomic) NSMutableData *buffer;
30@property(assign, nonatomic) UInt32 bufferOffset;
31
32@end
33
34
35@implementation TMemoryBuffer
36
37-(id) init
38{
39  if ((self = [super init])) {
40    _buffer = [NSMutableData new];
41    _bufferOffset = 0;
42  }
43  return self;
44}
45
46-(id) initWithData:(NSData *)data
47{
48  if (self = [super init]) {
49    _buffer = [data mutableCopy];
50    _bufferOffset = 0;
51  }
52  return self;
53}
54
55-(id) initWithDataNoCopy:(NSMutableData *)data
56{
57  if (self = [super init]) {
58    _buffer = data;
59    _bufferOffset = 0;
60  }
61  return self;
62}
63
64-(BOOL) readAll:(UInt8 *)outBuffer offset:(UInt32)outBufferOffset length:(UInt32)length error:(NSError *__autoreleasing *)error
65{
66  UInt32 got = [self readAvail:outBuffer offset:outBufferOffset maxLength:length error:error];
67  if (got != length) {
68
69    // Report underflow only if readAvail didn't report error already
70    if (error && !*error) {
71      *error = [NSError errorWithDomain:TTransportErrorDomain
72                                   code:TTransportErrorEndOfFile
73                               userInfo:nil];
74    }
75
76    return NO;
77  }
78
79  return YES;
80}
81
82-(UInt32) readAvail:(UInt8 *)outBuffer offset:(UInt32)outBufferOffset maxLength:(UInt32)maxLength error:(NSError *__autoreleasing *)error
83{
84  UInt32 avail = (UInt32)_buffer.length - _bufferOffset;
85  if (avail == 0) {
86    return 0;
87  }
88
89  NSRange range;
90  range.location = _bufferOffset;
91  range.length = MIN(maxLength, avail);
92
93  [_buffer getBytes:outBuffer + outBufferOffset range:range];
94  _bufferOffset += range.length;
95
96  if (_bufferOffset >= GARBAGE_BUFFER_SIZE) {
97    [_buffer replaceBytesInRange:NSMakeRange(0, _bufferOffset) withBytes:NULL length:0];
98    _bufferOffset = 0;
99  }
100
101  return (UInt32)range.length;
102}
103
104-(BOOL) write:(const UInt8 *)inBuffer offset:(UInt32)inBufferOffset length:(UInt32)length error:(NSError *__autoreleasing *)error
105{
106  [_buffer appendBytes:inBuffer + inBufferOffset length:length];
107
108  return YES;
109}
110
111-(NSData *) buffer
112{
113  return _buffer;
114}
115
116-(BOOL) flush:(NSError *__autoreleasing *)error
117{
118  return YES;
119}
120
121@end
122