Search code examples
c#arraysbase64byte

Combine and split byte arrays in C#


I want to create methods like this:

public byte[] TransformStringsIntoBytes(string[] base64EncodedStrings)
{
  // I want to combine multiple base64 encoded strings to a byte array
  // but I want to have the possibility to convert it back to multiple strings
}

public string[] TransformBytesIntoStrings(string[] byteArray)
{
  // Here I want to convert the byte array back to the strings
}

So I want to combine multiple base64 encoded strings to a byte array, but I want to have the possibility to convert it back to multiple strings. It is important that it is not a two dimensional byte array. Maybe a possibility will be insert a delimiter after each string (is there a standard delimiter for bytes?)


Solution

  • We can try exploiting the fact, that base64 encoded string uses 64 different characters when ASCI one can use as many as 128 and byte has 256 distinct values. So we can use any symbol from Ascii (or byte) which is not among base 64 as a delimiter. In the code below, I use \0 as such a delimiter:

    public byte[] TransformStringsIntoBytes(string[] base64EncodedStrings) {
      if (base64EncodedStrings is null)
        return null;
    
      var result = new byte[base64EncodedStrings.Sum(array => array.Length) + 
                            base64EncodedStrings.Length - 1];
    
      for (int i = 0, index = 0; i < base64EncodedStrings.Length; ++i) {
        var array = Encoding.ASCII.GetBytes(base64EncodedStrings[i]);
    
        if (i > 0)
          result[index++] = 0; // I use \0 as a delimiter
    
        Array.Copy(array, 0, result, index, array.Length);
    
        index += array.Length;
      }
    
      return result;
    }
    

    Reverse

    public string[] TransformBytesIntoStrings(byte[] byteArray) {
      if (byteArray is null)
        return null;
    
      var result = new List<string>();
    
      for (int i = 0, index = 0; i < byteArray.Length; ++i)
        if (byteArray[i] == 0) { // I use \0 as a delimiter
          result.Add(Encoding.ASCII.GetString(byteArray.AsSpan(index, i - index)));
    
          index = i + 1;
        }
        else if (i == byteArray.Length - 1)
          result.Add(Encoding.ASCII.GetString(byteArray.AsSpan(index)));
    
      return result.ToArray();
    }
    

    Here I assumed that none of base64EncodedStrings items can be null. If nulls are possible, you have to encode them as well, e.g. as \x0001 char:

    public byte[] TransformStringsIntoBytes(string?[] base64EncodedStrings){
      if (base64EncodedStrings is null)
        return null;
    
      var result = new byte[base64EncodedStrings.Sum(array => (array ?? "\x0001").Length) +
                            base64EncodedStrings.Length - 1];
    
      for (int i = 0, index = 0; i < base64EncodedStrings.Length; ++i) {
        var array = Encoding.ASCII.GetBytes(base64EncodedStrings[i] ?? "\x0001");
    
        if (i > 0)
          result[index++] = 0;
    
        Array.Copy(array, 0, result, index, array.Length);
    
        index += array.Length;
      }
    
      return result;
    }
    

    Reverse:

    public string[] TransformBytesIntoStrings(byte[] byteArray) {
      if (byteArray is null)
        return null;
    
      var result = new List<string>();
    
      for (int i = 0, index = 0; i < byteArray.Length; ++i)
        if (byteArray[i] == 0) {
          string st = Encoding.ASCII.GetString(byteArray.AsSpan(index, i - index));
    
          result.Add(st == "\x0001" ? null : st);
    
          index = i + 1;
        }
        else if (i == byteArray.Length - 1) {
          string st = Encoding.ASCII.GetString(byteArray.AsSpan(index));
    
          result.Add(st == "\x0001" ? null : st);
        }
    
      return result.ToArray();
    }