/// <summary> /// Copies the elements of the ICollection to an Array, starting at a particular Array index. /// </summary> /// <param name="array">The one-dimensional Array that is the destination of the elements copied from ICollection. The Array must have zero-based indexing.</param> /// <param name="arrayIndex">The zero-based index in array at which copying begins</param> public override void CopyTo(Sexp[] array, int arrayIndex) { for (int i = 0; i < Value.Count; i++) { array[arrayIndex + i] = new SexpArrayBool(Value[i]); } }
/// <summary> /// Determines whether the specified SexpArrayBool is equal to this instance. /// </summary> /// <param name="other"></param> /// <returns> /// <c>true</c> if the specified SexpArrayBool is equal to this instance; otherwise, <c>false</c>. /// Does not check for attribute equality. /// </returns> public bool Equals(SexpArrayBool other) { if (ReferenceEquals(null, other)) { return(false); } if (ReferenceEquals(this, other)) { return(true); } return(other.Value.SequenceEqual(Value)); }
/// <summary> /// Decode a Qap1-encoded Sexp /// </summary> /// <param name="data">The byte stream in which the Sexp is encoded</param> /// <param name="start">At which index of data does the Sexp begin?</param> /// <returns>The decoded Sexp.</returns> private static Sexp DecodeSexp(byte[] data, ref long start) { // pull sexp type byte xt = data[start]; // calculate length of payload var lengthBuf = new byte[8]; Array.Copy(data, start + 1, lengthBuf, 0, 3); start += 4; if ((xt & XtLarge) == XtLarge) { Array.Copy(data, start, lengthBuf, 3, 4); start += 4; xt -= XtLarge; } var length = ( long )BitConverter.ToUInt64(lengthBuf, 0); // has attributes? process first SexpTaggedList attrs = null; if ((xt & XtHasAttr) == XtHasAttr) { xt -= XtHasAttr; long oldstart = start; attrs = ( SexpTaggedList )DecodeSexp(data, ref start); length -= start - oldstart; } long end = start + length; Sexp result; switch (xt) { case XtNull: { if (length != 0) { throw new RserveException("Attempting to decode an SexpNull, but it is followed by data when it shouldn't be."); } result = new SexpNull(); } break; case XtSymName: { // keep all characters up to the first null var symnNamBuf = new byte[length]; Array.Copy(data, start, symnNamBuf, 0, length); string res = Encoding.UTF8.GetString(symnNamBuf); result = new SexpSymname(res.Split('\x00')[0]); } break; case XtArrayInt: { var res = new int[length / 4]; var intBuf = new byte[4]; for (long i = 0; i < length; i += 4) { Array.Copy(data, start + i, intBuf, 0, 4); res[i / 4] = BitConverter.ToInt32(intBuf, 0); } // is date or just an integer? if ((attrs != null) && (attrs.ContainsKey("class") && attrs["class"].AsStrings.Contains("Date"))) { result = new SexpArrayDate(res); } else { result = new SexpArrayInt(res); } } break; case XtArrayBool: { if (length < 4) { throw new RserveException("Decoding an SexpArrayBool where data doesn't seem to contain a data length field."); } var boolLengthBuf = new byte[4]; Array.Copy(data, start, boolLengthBuf, 0, 4); var datalength = BitConverter.ToInt32(boolLengthBuf, 0); if (datalength > length - 4) { throw new RserveException("Decoding an SexpArrayBool where transmitted data field too short for number of entries."); } var res = new bool?[datalength]; for (int i = 0; i < datalength; i++) { // R logical is false if 0, true if 1, and NA if 2 switch (data[start + i + 4]) { case 0: res[i] = false; break; case 1: res[i] = true; break; case 2: res[i] = null; break; default: throw new RserveException("Decoding an SexpArrayBool and found an element in the array that is not an R bool: " + data[start + i + 4]); } } result = new SexpArrayBool(res); } break; case XtArrayDouble: { var res = new double[length / 8]; var doubleBuf = new byte[8]; for (long i = 0; i < length; i += 8) { Array.Copy(data, start + i, doubleBuf, 0, 8); res[i / 8] = BitConverter.ToDouble(doubleBuf, 0); } // is date or just a double? if ((attrs != null) && (attrs.ContainsKey("class") && attrs["class"].AsStrings.Contains("Date"))) { result = new SexpArrayDate(res.Select(Convert.ToInt32)); } else { result = new SexpArrayDouble(res); } } break; case XtArrayString: { var res = new List <string>(); long i = 0; for (long j = 0; j < length; j++) { if (data[start + j] != 0) { continue; } if ((j == i + 1) && (data[start + i] == 255)) { res.Add(null); } else { if (data[start + i] == 255) { i++; } var stringBuf = new byte[j - i]; Array.Copy(data, start + i, stringBuf, 0, j - i); res.Add(Encoding.UTF8.GetString(stringBuf)); } i = j + 1; } result = new SexpArrayString(res); } break; case XtListNoTag: case XtLangNoTag: case XtVector: result = new SexpList(); while (start < end) { result.Add(DecodeSexp(data, ref start)); } break; case XtLangTag: case XtListTag: result = new SexpTaggedList(); while (start < end) { Sexp val = DecodeSexp(data, ref start); Sexp key = DecodeSexp(data, ref start); result.Add(key.IsNull ? String.Empty : key.AsString, val); } break; case XtRaw: { var d = new byte[length]; Array.Copy(data, start, d, 0, length); result = new SexpQap1Raw(xt, d); } break; default: throw new RserveException("Cannot decode an Sexp because the type is not recognized: " + xt); } if (start > end) { throw new RserveException("When decoding an Sexp, more data consumed than provided."); } start = end; if (attrs != null) { foreach (var a in attrs.AsSexpDictionary) { result.Attributes.Add(a.Key, a.Value); } } return(result); }