1# encoding: ascii-8bit
2#
3# Licensed to the Apache Software Foundation (ASF) under one
4# or more contributor license agreements. See the NOTICE file
5# distributed with this work for additional information
6# regarding copyright ownership. The ASF licenses this file
7# to you under the Apache License, Version 2.0 (the
8# "License"); you may not use this file except in compliance
9# with the License. You may obtain a copy of the License at
10#
11#   http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing,
14# software distributed under the License is distributed on an
15# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16# KIND, either express or implied. See the License for the
17# specific language governing permissions and limitations
18# under the License.
19#
20
21module Thrift
22  # A collection of utilities for working with bytes and byte buffers.
23  module Bytes
24    if RUBY_VERSION >= '1.9'
25      # Creates and empty byte buffer (String with BINARY encoding)
26      #
27      # size - The Integer size of the buffer (default: nil) to create
28      #
29      # Returns a String with BINARY encoding, filled with null characters
30      # if size is greater than zero
31      def self.empty_byte_buffer(size = nil)
32        if (size && size > 0)
33          "\0".force_encoding(Encoding::BINARY) * size
34        else
35          ''.force_encoding(Encoding::BINARY)
36        end
37      end
38
39      # Forces the encoding of the buffer to BINARY. If the buffer
40      # passed is frozen, then it will be duplicated.
41      #
42      # buffer - The String to force the encoding of.
43      #
44      # Returns the String passed with an encoding of BINARY; returned
45      # String may be a duplicate.
46      def self.force_binary_encoding(buffer)
47        buffer = buffer.dup if buffer.frozen?
48        buffer.force_encoding(Encoding::BINARY)
49      end
50
51      # Gets the byte value of a given position in a String.
52      #
53      # string - The String to retrive the byte value from.
54      # index  - The Integer location of the byte value to retrieve.
55      #
56      # Returns an Integer value between 0 and 255.
57      def self.get_string_byte(string, index)
58        string.getbyte(index)
59      end
60
61      # Sets the byte value given to a given index in a String.
62      #
63      # string - The String to set the byte value in.
64      # index  - The Integer location to set the byte value at.
65      # byte   - The Integer value (0 to 255) to set in the string.
66      #
67      # Returns an Integer value of the byte value to set.
68      def self.set_string_byte(string, index, byte)
69        string.setbyte(index, byte)
70      end
71
72      # Converts the given String to a UTF-8 byte buffer.
73      #
74      # string - The String to convert.
75      #
76      # Returns a new String with BINARY encoding, containing the UTF-8
77      # bytes of the original string.
78      def self.convert_to_utf8_byte_buffer(string)
79        if string.encoding != Encoding::UTF_8
80          # transcode to UTF-8
81          string = string.encode(Encoding::UTF_8)
82        else
83          # encoding is already UTF-8, but a duplicate is needed
84          string = string.dup
85        end
86        string.force_encoding(Encoding::BINARY)
87      end
88
89      # Converts the given UTF-8 byte buffer into a String
90      #
91      # utf8_buffer - A String, with BINARY encoding, containing UTF-8 bytes
92      #
93      # Returns a new String with UTF-8 encoding,
94      def self.convert_to_string(utf8_buffer)
95        # duplicate the buffer, force encoding to UTF-8
96        utf8_buffer.dup.force_encoding(Encoding::UTF_8)
97      end
98    else
99      def self.empty_byte_buffer(size = nil)
100        if (size && size > 0)
101          "\0" * size
102        else
103          ''
104        end
105      end
106
107      def self.force_binary_encoding(buffer)
108        buffer
109      end
110
111      def self.get_string_byte(string, index)
112        string[index]
113      end
114
115      def self.set_string_byte(string, index, byte)
116        string[index] = byte
117      end
118
119      def self.convert_to_utf8_byte_buffer(string)
120        # This assumes $KCODE is 'UTF8'/'U', which would mean the String is already a UTF-8 byte buffer
121        # TODO consider handling other $KCODE values and transcoding with iconv
122        string
123      end
124
125      def self.convert_to_string(utf8_buffer)
126        # See comment in 'convert_to_utf8_byte_buffer' for relevant assumptions.
127        utf8_buffer
128      end
129    end
130  end
131end
132