public static PhpBytes GzCompress(PhpBytes data, int level) { if ((level < -1) || (level > 9)) { PhpException.Throw(PhpError.Warning, String.Format("compression level ({0}) must be within -1..9", level)); return(null); } int length_bound = data.Length + (data.Length / PHP_ZLIB_MODIFIER) + 15 + 1; byte[] output; try { output = new byte[length_bound]; } catch (OutOfMemoryException) { return(null); } int status; status = ZlibCompress(ref output, data.ReadonlyData, level); if (status == zlibConst.Z_OK) { return(new PhpBytes(output)); } else { PhpException.Throw(PhpError.Warning, zError(status)); return(null); } }
private static Value _md5(FlowController flow, Value[] arguments) { stringConverter.SetContext(flow); var stringValue = stringConverter.EvaluateToString(arguments[0]); if (stringValue == null) { return(flow.OutSet.AnyStringValue); } var phpBytes = new PhpBytes(stringValue.Value); Debug.Assert(arguments.Length > 0); if (arguments.Length > 1) { booleanConverter.SetContext(flow.OutSet.Snapshot); var isRawOutput = booleanConverter.EvaluateToBoolean(arguments[1]); if ((isRawOutput == null) || isRawOutput.Value) { // TODO: Implement precisely return(flow.OutSet.AnyStringValue); } } return(flow.OutSet.CreateString(PhpHash.MD5(phpBytes))); }
/// <summary> /// Deserializes a graph of connected object from a byte array using a given formatter. /// </summary> /// <param name="bytes">The byte array to deserialize the graph from.</param> /// <param name="caller">DTypeDesc of the caller's class context if it is known or UnknownTypeDesc if it should be determined lazily.</param> /// <returns> /// The deserialized object graph or an instance of <see cref="PhpReference"/> containing <B>false</B> on error. /// </returns> /// <exception cref="PhpException">Deserialization failed (Notice).</exception> public PhpReference Deserialize(PhpBytes bytes, DTypeDesc caller) { MemoryStream stream = new MemoryStream(bytes.ReadonlyData); object result = null; try { try { // deserialize the data result = GetFormatter(caller).Deserialize(stream); } catch (System.Reflection.TargetInvocationException e) { throw e.InnerException; } } catch (SerializationException e) { PhpException.Throw(PhpError.Notice, LibResources.GetString("deserialization_failed", e.Message, stream.Position, stream.Length)); return(new PhpReference(false)); } return(PhpVariable.MakeReference(result)); }
public static string EncodeBase64(PhpBytes data_to_encode) { if (data_to_encode == null) { return(null); } return(System.Convert.ToBase64String(data_to_encode.ReadonlyData)); }
public static PhpReference Unserialize(PhpBytes json) { if (json == null) { return(null); } return(PhpJsonSerializer.Default.Deserialize(json, UnknownTypeDesc.Singleton)); }
public static string Encode(PhpBytes bytes) { byte[] data = (bytes != null) ? bytes.ReadonlyData : ArrayUtils.EmptyBytes; StringBuilder result = new StringBuilder((int)(data.Length * 1.38 + data.Length + 1)); Encode(data, new StringWriter(result)); return(result.ToString()); }
private void AddFormData(object data) { //currentData.Type = FormType.FORM_CONTENT; PhpBytes bytes = PhpVariable.AsBytes(data); currentData.Data = bytes.ReadonlyData; NextDataIsFooter(); }
static void Concat() { PhpBytes a = new PhpBytes(new byte[] { 61, 62, 63 }); string b = "-hello-"; PhpBytes c = new PhpBytes(new byte[] { 61, 61, 61 }); string d = "-bye-"; object result = Operators.Concat(a, b, c, d); Assert.IsTrue(Operators.StrictEquality(result, "=>?-hello-===-bye-")); }
public static PhpReference Unserialize(PHP.Core.Reflection.DTypeDesc caller, PhpBytes bytes) { if (bytes == null || bytes.Length == 0) { return(new PhpReference(false)); } LibraryConfiguration config = LibraryConfiguration.GetLocal(ScriptContext.CurrentContext); return(config.Serialization.DefaultSerializer.Deserialize(bytes, caller)); }
private static string StrrChr(object haystack, object needle, bool beforeNeedle /*=false*/, getEncoding encodingGetter, bool ignoreCase) { string uhaystack = ObjectToString(haystack, encodingGetter); char cneedle; { string uneedle; if (needle is string) { uneedle = (string)needle; } else if (needle is PhpString) { uneedle = ((IPhpConvertible)needle).ToString(); } else if (needle is PhpBytes) { Encoding encoding = encodingGetter(); if (encoding == null) { return(null); } PhpBytes bytes = (PhpBytes)needle; uneedle = encoding.GetString(bytes.ReadonlyData, 0, bytes.Length); } else { // needle as a character number Encoding encoding = encodingGetter(); if (encoding == null) { return(null); } uneedle = encoding.GetString(new byte[] { unchecked ((byte)Core.Convert.ObjectToInteger(needle)) }, 0, 1); } if (string.IsNullOrEmpty(uneedle)) { return(null); } cneedle = uneedle[0]; } int index = (ignoreCase) ? uhaystack.ToLower().LastIndexOf(char.ToLower(cneedle)) : uhaystack.LastIndexOf(cneedle); if (index < 0) { return(null); } return((beforeNeedle) ? uhaystack.Remove(index) : uhaystack.Substring(index)); }
public static PhpBytes GzDeflate(PhpBytes data, int level) { if ((level < -1) || (level > 9)) { PhpException.Throw(PhpError.Warning, String.Format("compression level ({0}) must be within -1..9", level)); return(null); } ZStream zs = new ZStream(); zs.next_in = data.ReadonlyData; zs.avail_in = data.Length; // heuristic for max data length zs.avail_out = data.Length + data.Length / PHP_ZLIB_MODIFIER + 15 + 1; zs.next_out = new byte[zs.avail_out]; // -15 omits the header (undocumented feature of zlib) int status = zs.deflateInit(level, -MAX_WBITS); if (status == zlibConst.Z_OK) { status = zs.deflate(zlibConst.Z_FINISH); if (status != zlibConst.Z_STREAM_END) { zs.deflateEnd(); if (status == zlibConst.Z_OK) { status = zlibConst.Z_BUF_ERROR; } } else { status = zs.deflateEnd(); } } if (status == zlibConst.Z_OK) { byte[] result = new byte[zs.total_out]; Buffer.BlockCopy(zs.next_out, 0, result, 0, (int)zs.total_out); return(new PhpBytes(result)); } else { PhpException.Throw(PhpError.Warning, zError(status)); return(null); } }
public override object Filter(object input, bool closing) { PhpBytes bInput = Core.Convert.ObjectToPhpBytes(input); if (bInput != null) { int offset = 0; return(new PhpBytes(FilterInner(bInput.ReadonlyData, ref offset, closing))); } else { Debug.Fail("InflateFilter expects chunks to be convertible to PhpBytes."); return(null); } }
public override object GetValue(Literal node) { var value = node.ValueObj; if (value != null) { // wrap CLR value to PHP value type if (value.GetType() == typeof(byte[])) { value = new PhpBytes((byte[])value); } } Debug.Assert(PhpVariable.HasLiteralPrimitiveType(value)); return(value); }
public static PhpReference Unserialize(PhpBytes json, bool assoc /* = false*/, int depth /* = 512*/, JsonDecodeOptions options /* = 0 */) { if (json == null) { return(null); } return(new PhpJsonSerializer( new JsonFormatter.EncodeOptions(), new JsonFormatter.DecodeOptions() { Assoc = assoc, Depth = depth, BigIntAsString = (options & JsonDecodeOptions.JSON_BIGINT_AS_STRING) != 0 } ).Deserialize(json, UnknownTypeDesc.Singleton)); }
/// <summary> /// Converts PhpBytes using specified encoding. If any other object is provided, encoding is not performed. /// </summary> /// <param name="str"></param> /// <param name="encodingGetter"></param> /// <returns></returns> private static string ObjectToString(object str, getEncoding encodingGetter) { if (str is PhpBytes) { PhpBytes bytes = (PhpBytes)str; Encoding encoding = encodingGetter(); if (encoding == null) { return(null); } return(encoding.GetString(bytes.ReadonlyData, 0, bytes.Length)); } else { // .NET String should be always UTF-16, given encoding is irrelevant return(PHP.Core.Convert.ObjectToString(str)); } }
public static PhpBytes GzUncompress(PhpBytes data, int length) { if (length < 0) { PhpException.Throw(PhpError.Warning, String.Format("length {0} must be greater or equal zero", length)); return(null); } int ilength; int factor = 1, maxfactor = 16; byte[] output; int status; do { ilength = length != 0 ? length : (data.Length * (1 << factor++)); try { output = new byte[ilength]; } catch (OutOfMemoryException) { return(null); } status = ZlibUncompress(ref output, data.ReadonlyData); }while ((status == zlibConst.Z_BUF_ERROR) && (length == 0) && (factor < maxfactor)); if (status == zlibConst.Z_OK) { return(new PhpBytes(output)); } else { PhpException.Throw(PhpError.Warning, zError(status)); return(null); } }
private void Callback(IAsyncResult ar) { if (access == StreamAccessOptions.Read) { int count = stream.EndRead(ar); if (count > 0) { if (count != buffer.Length) { // TODO: improve streams var buf = new byte[count]; Buffer.BlockCopy(buffer.ReadonlyData, 0, buf, 0, count); phpStream.WriteBytes(new PhpBytes(buf)); } else { phpStream.WriteBytes(buffer); } stream.BeginRead(buffer.Data, 0, buffer.Length, callback, ar.AsyncState); } else { stream.Close(); } } else { buffer = phpStream.ReadBytes(BufferSize); if (buffer != null) { stream.BeginWrite(buffer.ReadonlyData, 0, buffer.Length, callback, ar.AsyncState); } else { stream.EndWrite(ar); stream.Close(); } } }
public static string GuidToString(PhpBytes binary, bool shortFormat) { if (binary == null || binary.Length == 0) { return(String.Empty); } if (binary.Length != 16) { PhpException.InvalidArgument("binary", LibResources.GetString("arg:invalid_length")); return(null); } if (shortFormat) { return(new Guid(binary.ReadonlyData).ToString("D").ToUpper()); } else { return(PHP.Core.StringUtils.BinToHex(binary.ReadonlyData, null).ToUpper()); } }
/// <summary> /// Compress given data using compressor named in contentEncoding. Set the response header accordingly. /// </summary> /// <param name="data">PhpBytes or string to be compressed.</param> /// <param name="httpcontext">Current HttpContext.</param> /// <param name="contentEncoding">gzip or deflate</param> /// <returns>Byte stream of compressed data.</returns> private static PhpBytes DoGzipHandler(object data, HttpContext /*!*/ httpcontext, ContentEncoding contentEncoding) { PhpBytes phpbytes = data as PhpBytes; var inputbytes = (phpbytes != null) ? phpbytes.ReadonlyData : Configuration.Application.Globalization.PageEncoding.GetBytes(PHP.Core.Convert.ObjectToString(data)); using (var outputStream = new System.IO.MemoryStream()) { System.IO.Stream compressionStream; switch (contentEncoding) { case ContentEncoding.gzip: compressionStream = new System.IO.Compression.GZipStream(outputStream, System.IO.Compression.CompressionMode.Compress); break; case ContentEncoding.deflate: compressionStream = new System.IO.Compression.DeflateStream(outputStream, System.IO.Compression.CompressionMode.Compress); break; default: throw new ArgumentException("Not recognized content encoding to be compressed to.", "contentEncoding"); } using (compressionStream) { compressionStream.Write(inputbytes, 0, inputbytes.Length); } //Debug.Assert( // ScriptContext.CurrentContext.Headers["content-encoding"] != contentEncoding, // "The content encoding was already set to '" + contentEncoding + "'. The ob_gzhandler() was called subsequently probably."); ScriptContext.CurrentContext.Headers["content-encoding"] = contentEncoding.ToString(); return(new PhpBytes(outputStream.ToArray())); } }
/// <summary> /// /// </summary> /// <param name="value"></param> /// <remarks>TODO: move to CodeGenerator.</remarks> internal void EmitLoadPhpBytes(PhpBytes/*!*/ value) { Debug.Assert(value != null); // create array of bytes LdcI4(value.Length); Emit(OpCodes.Newarr, typeof(byte)); if (value.Length > 0) // not valid for zero-length byte arrays { FieldBuilder datafld = this.DefineInitializedData( string.Concat("byte'", value.ReadonlyData.Length.ToString("x"), "'", value.ReadonlyData.GetHashCode().ToString()), value.ReadonlyData, FieldAttributes.Assembly | FieldAttributes.Static); Emit(OpCodes.Dup); Emit(OpCodes.Ldtoken, datafld); Emit(OpCodes.Call, Methods.InitializeArray); } Emit(OpCodes.Newobj, Constructors.PhpBytes_ByteArray); }
public static int GzWrite(PhpResource zp, PhpBytes str) { return(GzWrite(zp, str, -1)); }
public static int GzPutString(PhpResource zp, PhpBytes str, int length) { return(GzWrite(zp, str, length)); }
public static PhpReference Unserialize(PhpBytes json, bool assoc /* = false*/, int depth /* = 512*/) { return(Unserialize(json, assoc, depth, JsonDecodeOptions.Default)); }
public static int GzWrite(PhpResource zp, PhpBytes str, int length) { return(PhpFile.Write(zp, str, length)); }
/// <summary> /// Initializes a new instance of the StringLiteral class. /// </summary> public BinaryStringLiteral(Position position, PhpBytes /*!*/ value) : base(position) { this.value = value; }
public static PhpBytes exif_thumbnail(string filename, PhpReference width, PhpReference height, PhpReference imagetype) { if (string.IsNullOrEmpty(filename)) { PhpException.Throw(PhpError.Warning, Utils.Resources.GetString("filename_cannot_be_empty")); return(null); } if (imagetype != null) { PhpException.ArgumentValueNotSupported("imagetype", "!=null"); } Bitmap thumbnail = null; PhpBytes bytes, result; bytes = Utils.ReadPhpBytes(filename); if (bytes == null) { return(null); } // get thumbnail from <filename>'s content: using (MemoryStream ms = new MemoryStream(bytes.ReadonlyData)) { try { using (Bitmap image = (Bitmap)Image.FromStream(ms)) { thumbnail = (Bitmap)image.GetThumbnailImage(0, 0, () => true, IntPtr.Zero); } } catch { return(null); } } if (thumbnail == null) { return(null); } // if (width != null) { width.Value = thumbnail.Width; } if (height != null) { height.Value = thumbnail.Height; } using (MemoryStream ms2 = new MemoryStream()) { thumbnail.Save(ms2, ImageFormat.Png); result = new PhpBytes(ms2.GetBuffer()); } thumbnail.Dispose(); return(result); }
public void UploadData(object data) { PhpBytes bytes = PhpVariable.AsBytes(data); UploadData(bytes.ReadonlyData); }
/// <summary> /// Called only by Analyzer. On this instance Analyze method will not be called. /// </summary> internal BinaryStringLiteral(Position position, PhpBytes value, AccessType access) : base(position) { this.value = value; this.access = access; }
public override object Filter(object input, bool closing) { // TODO: not the most efficient method - after the filters are upgraded to bucket lists, update this PhpBytes bInput = Core.Convert.ObjectToPhpBytes(input); if (bInput != null) { if (_state == UncompressionState.Failed) { // failed filter should not get any more calls PhpException.Throw(PhpError.Warning, "using filter in failed state"); return(null); } if (_state == UncompressionState.PostTrailer) { // post trailer - ignore everything if (closing) { _state = UncompressionState.Finished; } return(new PhpBytes()); } if (_state == UncompressionState.Finished) { // finished filter should not get any more data PhpException.Throw(PhpError.Warning, "using filter in finished state"); return(null); } if (_state == UncompressionState.Passthrough) { // this is not gzip data format - pass the data through return(new PhpBytes(bInput)); } // enqueue the block _chunkQueue.EnqueueByteBlock(bInput.ReadonlyData, 0, bInput.Length); if (_state == UncompressionState.Header) { #region Header handling //beginning of the stream byte[] beginning = _chunkQueue.DequeueByteBlock(Zlib.GZIP_HEADER_LENGTH); if (beginning == null && !closing) { // we do not have enough data, but we know there would be more data ahead return(new PhpBytes()); } else { //check the header format if (beginning.Length >= 2 && beginning[0] == Zlib.GZIP_HEADER[0] && beginning[1] == Zlib.GZIP_HEADER[1]) { //header magic bytes are OK if (beginning.Length < Zlib.GZIP_HEADER_LENGTH) { // header is too short -> this is an error PhpException.Throw(PhpError.Warning, "unexpected end of file"); return(null); } else { // check the rest of the header if (beginning[2] != Zlib.Z_DEFLATED) { PhpException.Throw(PhpError.Warning, "unknown compression method"); return(null); } if ((beginning[3] & Zlib.GZIP_HEADER_RESERVED_FLAGS) != 0) { PhpException.Throw(PhpError.Warning, "unknown header flags set"); return(null); } _headerFlags = beginning[3]; //change the header state based on the header flags UpdateHeaderState(); } } else { // this is not a gzip format -> passthrough the data _state = UncompressionState.Passthrough; return(new PhpBytes(beginning)); } } #endregion } if (_state == UncompressionState.HeaderExtraField) { #region Header Extra Field Handling if (_extraHeaderLength == null) { //length was not yet detected if (_chunkQueue.AvailableBytes < 2) { //wait for more input return(new PhpBytes()); } else { //assemble length _extraHeaderLength = _chunkQueue.DequeueByte(); _extraHeaderLength &= (_chunkQueue.DequeueByte() << 8); } } if (_extraHeaderLength != null) { //length was already read if (_chunkQueue.AvailableBytes < _extraHeaderLength) { //wait for more input return(new PhpBytes()); } else { Debug.Assert(_extraHeaderLength.HasValue); //skip the extra header _chunkQueue.SkipByteBlock(_extraHeaderLength.Value); UpdateHeaderState(); } } #endregion } if (_state == UncompressionState.HeaderFilename || _state == UncompressionState.HeaderComment) { #region Header Filename and Comment Handling // filename or comment // cycle until input ends or zero character is encountered while (true) { byte?nextByte = _chunkQueue.DequeueByte(); if (nextByte == null) { //wait for more input return(new PhpBytes()); } if (nextByte == 0) { // end the cycle break; } } // go to the next state UpdateHeaderState(); #endregion } if (_state == UncompressionState.HeaderCRC) { #region CRC Handling // header CRC if (_chunkQueue.AvailableBytes < 2) { //wait for more input return(new PhpBytes()); } else { //skip the CRC _chunkQueue.DequeueByte(); _chunkQueue.DequeueByte(); UpdateHeaderState(); } #endregion } //filled by data handling and sometimes returned by trailer handling byte[] output = null; if (_state == UncompressionState.Data) { #region Deflated Data Handling //get all available bytes byte[] inputBytes = _chunkQueue.DequeueByteBlock(_chunkQueue.AvailableBytes); int inputOffset = 0; // perform the inner operation try { output = FilterInner(inputBytes, ref inputOffset, closing); } catch { // exception was thrown _state = UncompressionState.Failed; throw; } if (output == null) { // error happened and exception was not thrown _state = UncompressionState.Failed; return(null); } // update the hash algorithm _crc.Update(output); if (inputOffset != inputBytes.Length) { // push the rest of the data into the chunk queue _chunkQueue.PushByteBlock(inputBytes, inputOffset, inputBytes.Length - inputOffset); // end of deflated block reached _state = UncompressionState.Trailer; // pass through to Trailer handling } else { //normal decompressed block - return it return(new PhpBytes(output)); } #endregion } if (_state == UncompressionState.Trailer) { #region Trailer Handling // the deflate block has already ended, we are processing trailer if (closing || _chunkQueue.AvailableBytes >= Zlib.GZIP_FOOTER_LENGTH) { byte[] trailer; trailer = _chunkQueue.DequeueByteBlock(_chunkQueue.AvailableBytes); if (trailer.Length >= Zlib.GZIP_FOOTER_LENGTH) { byte[] crc = _crc.Final(); if (crc[3] != trailer[0] || crc[2] != trailer[1] || crc[1] != trailer[2] || crc[0] != trailer[3]) { _state = UncompressionState.Failed; PhpException.Throw(PhpError.Warning, "incorrect data check"); return(null); } if (BitConverter.ToInt32(trailer, 4) != _stream.total_out) { _state = UncompressionState.Failed; PhpException.Throw(PhpError.Warning, "incorrect length check"); return(null); } _state = closing ? UncompressionState.Finished : UncompressionState.PostTrailer; // everything is fine, return the output if available return(output != null ? new PhpBytes(output) : new PhpBytes()); } else { _state = UncompressionState.Failed; PhpException.Throw(PhpError.Warning, "unexpected end of file"); return(null); } } else { //stream is not closing yet - return the remaining output, otherwise empty return(output != null ? new PhpBytes(output) : new PhpBytes()); } #endregion } //this should not happen Debug.Fail(null); return(null); } else { Debug.Fail("GzipUncompressionFilter expects chunks to be convertible to PhpBytes."); return(null); } }
public override object Filter(object input, bool closing) { PhpBytes bInput = Core.Convert.ObjectToPhpBytes(input); if (bInput != null) { if (_state == CompressionState.Failed) { PhpException.Throw(PhpError.Warning, "using filter in failed state"); return(null); } if (_state == CompressionState.Finished) { PhpException.Throw(PhpError.Warning, "using filter in finished state"); return(null); } byte[] header = null; byte[] footer = null; if (_state == CompressionState.Header) { header = new byte[Zlib.GZIP_HEADER_LENGTH]; header[0] = Zlib.GZIP_HEADER[0]; header[1] = Zlib.GZIP_HEADER[1]; header[2] = Zlib.Z_DEFLATED; header[3] = 0; // 3-8 represent time and are set to zero header[9] = Zlib.OS_CODE; _crc.Init(); _state = CompressionState.Data; } int outputOffset = 0; byte[] output; try { output = FilterInner(bInput.ReadonlyData, ref outputOffset, closing); } catch { _state = CompressionState.Failed; throw; } if (output == null) { _state = CompressionState.Failed; return(null); } // input should be read to the end Debug.Assert(outputOffset == bInput.Length); _crc.Update(bInput.ReadonlyData); if (closing) { byte[] crcBytes = _crc.Final(); footer = new byte[Zlib.GZIP_FOOTER_LENGTH]; // well this implementation simply has the hash inverted compared to C implementation footer[0] = crcBytes[3]; footer[1] = crcBytes[2]; footer[2] = crcBytes[1]; footer[3] = crcBytes[0]; footer[4] = (byte)(_stream.total_in & 0xFF); footer[5] = (byte)((_stream.total_in >> 8) & 0xFF); footer[6] = (byte)((_stream.total_in >> 16) & 0xFF); footer[7] = (byte)((_stream.total_in >> 24) & 0xFF); _state = CompressionState.Finished; } if (header != null || footer != null) { int offset = 0; byte[] appended = new byte[(header != null ? header.Length : 0) + output.Length + (footer != null ? footer.Length : 0)]; if (header != null) { Buffer.BlockCopy(header, 0, appended, 0, header.Length); offset += header.Length; } if (output != null && output.Length > 0) { Buffer.BlockCopy(output, 0, appended, offset, output.Length); offset += output.Length; } if (footer != null) { Buffer.BlockCopy(footer, 0, appended, offset, footer.Length); } return(new PhpBytes(appended)); } else { return(new PhpBytes(output)); } } else { Debug.Fail("GzipCompresionFilter expects chunks to be of type PhpBytes."); return(null); } }
/// <summary> /// Initializes a new instance of the StringLiteral class. /// </summary> public BinaryStringLiteral(Position position, PhpBytes/*!*/ value) : base(position) { this.value = value; }
public static PhpArray Unpack(string format, PhpBytes data) { if (format == null) { return(null); } byte[] buffer = (data != null) ? data.ReadonlyData : ArrayUtils.EmptyBytes; Encoding encoding = Configuration.Application.Globalization.PageEncoding; byte[] reversed = new byte[4]; // used for reversing the order of bytes in buffer int i = 0; int pos = 0; PhpArray result = new PhpArray(); while (i < format.Length) { string name; int repeater; char specifier; // parses specifier, repeater, and name from the format string: ParseFormatToken(format, ref i, out specifier, out repeater, out name); int remains = buffer.Length - pos; // the number of bytes remaining in the buffer int size; // a size of data to be extracted corresponding to the specifier // repeater of '@' specifier has a special meaning: if (specifier == '@') { if (repeater > buffer.Length || repeater == InfiniteRepeater) { PhpException.Throw(PhpError.Warning, LibResources.GetString("outside_string", specifier)); } else { pos = repeater; } continue; } // number of operations: int op_count; // gets the size of the data to read and adjust repeater: if (!GetSizeToUnpack(specifier, remains, repeater, out op_count, out size)) { PhpException.Throw(PhpError.Warning, LibResources.GetString("unknown_format_code", specifier)); return(null); } // repeats operation determined by specifier "op_count" times; // if op_count is infinite then stops when the number of remaining characters is zero: for (int j = 0; j < op_count || op_count == InfiniteRepeater; j++) { if (size > remains) { // infinite means "while data are available": if (op_count == InfiniteRepeater) { break; } PhpException.Throw(PhpError.Warning, LibResources.GetString("not_enought_input", specifier, size, remains)); return(null); } object item; switch (specifier) { case 'X': // decreases position, no value stored: if (pos == 0) { PhpException.Throw(PhpError.Warning, LibResources.GetString("outside_string", specifier)); } else { pos--; } continue; case 'x': // advances position, no value stored pos++; continue; case 'a': // NUL-padded string case 'A': // SPACE-padded string { byte pad = (byte)(specifier == 'a' ? 0x00 : 0x20); int last = pos + size - 1; while (last >= pos && buffer[last] == pad) { last--; } item = encoding.GetString(buffer, pos, last - pos + 1); break; } case 'h': // Hex string, low/high nibble first - converts to a string, takes n hex digits from string: case 'H': { int p = pos; int nibble_shift = (specifier == 'h') ? 0 : 4; StringBuilder sb = new StringBuilder(size); for (int k = 0; k < size; k++) { const string hex_digits = "0123456789ABCDEF"; sb.Append(hex_digits[(buffer[p] >> nibble_shift) & 0x0f]); // beware of odd repeaters! if (repeater == InfiniteRepeater || repeater > sb.Length) { sb.Append(hex_digits[(buffer[p] >> (4 - nibble_shift)) & 0x0f]); } p++; } item = sb.ToString(); break; } case 'c': // signed char item = (int)unchecked ((sbyte)buffer[pos]); break; case 'C': // unsigned char item = (int)buffer[pos]; break; case 's': // signed short (always 16 bit, machine byte order) item = (int)BitConverter.ToInt16(buffer, pos); break; case 'S': // unsigned short (always 16 bit, machine byte order) item = (int)BitConverter.ToUInt16(buffer, pos); break; case 'n': // unsigned short (always 16 bit, big endian byte order) if (BitConverter.IsLittleEndian) { item = (int)BitConverter.ToUInt16(LoadReverseBuffer(reversed, buffer, pos, 2), 0); } else { item = (int)BitConverter.ToUInt16(buffer, pos); } break; case 'v': // unsigned short (always 16 bit, little endian byte order) if (!BitConverter.IsLittleEndian) { item = (int)BitConverter.ToUInt16(LoadReverseBuffer(reversed, buffer, pos, 2), 0); } else { item = (int)BitConverter.ToUInt16(buffer, pos); } break; case 'i': // signed integer (machine dependent size and byte order - always 32 bit) case 'I': // unsigned integer (machine dependent size and byte order - always 32 bit) case 'l': // signed long (always 32 bit, machine byte order) case 'L': // unsigned long (always 32 bit, machine byte order) item = BitConverter.ToInt32(buffer, pos); break; case 'N': // unsigned long (always 32 bit, big endian byte order) item = unchecked (((int)buffer[pos] << 24) + (buffer[pos + 1] << 16) + (buffer[pos + 2] << 8) + buffer[pos + 3]); break; case 'V': // unsigned long (always 32 bit, little endian byte order) item = unchecked (((int)buffer[pos + 3] << 24) + (buffer[pos + 2] << 16) + (buffer[pos + 1] << 8) + buffer[pos + 0]); break; case 'f': // float (machine dependent size and representation - size is always 4B) item = (double)BitConverter.ToSingle(buffer, pos); break; case 'd': // double (machine dependent size and representation - size is always 8B) item = BitConverter.ToDouble(buffer, pos); break; default: Debug.Fail("Invalid specifier."); return(null); } AddValue(result, name, item, op_count, j); pos += size; remains -= size; } } return(result); }