Home | History | Annotate | Download | only in private
      1 /*
      2  *
      3  * Copyright 2015 gRPC authors.
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  *
     17  */
     18 
     19 #import "NSData+GRPC.h"
     20 
     21 #include <grpc/byte_buffer.h>
     22 #include <grpc/byte_buffer_reader.h>
     23 #include <string.h>
     24 
     25 // TODO(jcanizales): Move these two incantations to the C library.
     26 
     27 static void MallocAndCopyByteBufferToCharArray(grpc_byte_buffer *buffer, size_t *length,
     28                                                char **array) {
     29   grpc_byte_buffer_reader reader;
     30   if (!grpc_byte_buffer_reader_init(&reader, buffer)) {
     31     // grpc_byte_buffer_reader_init can fail if the data sent by the server
     32     // could not be decompressed for any reason. This is an issue with the data
     33     // coming from the server and thus we want the RPC to fail with error code
     34     // INTERNAL.
     35     *array = NULL;
     36     *length = 0;
     37     return;
     38   }
     39   // The slice contains uncompressed data even if compressed data was received
     40   // because the reader takes care of automatically decompressing it
     41   grpc_slice slice = grpc_byte_buffer_reader_readall(&reader);
     42   size_t uncompressed_length = GRPC_SLICE_LENGTH(slice);
     43   char *result = malloc(uncompressed_length);
     44   if (result) {
     45     memcpy(result, GRPC_SLICE_START_PTR(slice), uncompressed_length);
     46   }
     47   grpc_slice_unref(slice);
     48   *array = result;
     49   *length = uncompressed_length;
     50 
     51   grpc_byte_buffer_reader_destroy(&reader);
     52 }
     53 
     54 static grpc_byte_buffer *CopyCharArrayToNewByteBuffer(const char *array, size_t length) {
     55   grpc_slice slice = grpc_slice_from_copied_buffer(array, length);
     56   grpc_byte_buffer *buffer = grpc_raw_byte_buffer_create(&slice, 1);
     57   grpc_slice_unref(slice);
     58   return buffer;
     59 }
     60 
     61 @implementation NSData (GRPC)
     62 + (instancetype)grpc_dataWithByteBuffer:(grpc_byte_buffer *)buffer {
     63   if (buffer == NULL) {
     64     return nil;
     65   }
     66   char *array;
     67   size_t length;
     68   MallocAndCopyByteBufferToCharArray(buffer, &length, &array);
     69   if (!array) {
     70     // TODO(jcanizales): grpc_byte_buffer is reference-counted, so we can
     71     // prevent this memory problem by implementing a subclass of NSData
     72     // that wraps the grpc_byte_buffer. Then enumerateByteRangesUsingBlock:
     73     // can be implemented using a grpc_byte_buffer_reader.
     74     return nil;
     75   }
     76   // Not depending upon size assumption of NSUInteger
     77   NSUInteger length_max = MIN(length, UINT_MAX);
     78   return [self dataWithBytesNoCopy:array length:length_max freeWhenDone:YES];
     79 }
     80 
     81 - (grpc_byte_buffer *)grpc_byteBuffer {
     82   // Some implementations of NSData, as well as grpc_byte_buffer, support O(1)
     83   // appending of byte arrays by not using internally a single contiguous memory
     84   // block for representation.
     85   // The following implementation is thus not optimal, sometimes requiring two
     86   // copies (one by self.bytes and another by grpc_slice_from_copied_buffer).
     87   // If it turns out to be an issue, we can use enumerateByteRangesUsingblock:
     88   // to create an array of grpc_slice objects to pass to
     89   // grpc_raw_byte_buffer_create.
     90   // That would make it do exactly one copy, always.
     91   return CopyCharArrayToNewByteBuffer((const char *)self.bytes, (size_t)self.length);
     92 }
     93 @end
     94