/
Binary.prg
367 lines (308 loc) · 12.2 KB
/
Binary.prg
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
//
// Copyright (c) XSharp B.V. All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
// See License.txt in the project root for license information.
//
USING System
USING System.Text
USING System.Runtime.InteropServices
USING System.Runtime.CompilerServices
USING System.Diagnostics
USING System.Runtime.Serialization
#pragma options ("az", ON)
#include "attributes.xh"
BEGIN NAMESPACE XSharp
/// <summary>Internal type that implements the FoxPro Compatible BINARY type.<br/>
/// This type has many operators and implicit converters that normally are never directly called from user code.
/// The data in this type is stored as an array of Bytes<br/>
/// Conversions from and to String are supported and they use the current active windows codepage.
/// </summary>
[DebuggerDisplay("{ToDebugString(),nq}")];
[Serializable];
PUBLIC STRUCTURE __Binary IMPLEMENTS IFormattable, ;
IComparable<__Binary>, ;
IEquatable<__Binary>, ;
IComparable, ;
ISerializable
[NOSHOW] PRIVATE INITONLY _value AS BYTE[]
#region constructors
/// <include file="RTComments.xml" path="Comments/Constructor/*" />
/// <param name="b">Byte[] value that has the bytes that define the binary</param>
[NODEBUG] [INLINE];
CONSTRUCTOR (b AS BYTE[])
IF b == NULL
THROW NullError()
ENDIF
SELF:_value := b
/// <include file="RTComments.xml" path="Comments/Constructor/*" />
/// <param name="s">STRING that will be converted to bytes using the current windows codepage.</param>
/// <remarks>Accented characters and characters outside the current windows codepage may be replaced with a question mark.
/// and when the current codepage is a so called multi byte codepage than one character may be mapped to more than one byte in the result</remarks>
[NODEBUG] [INLINE];
CONSTRUCTOR (s AS STRING)
IF s == NULL
THROW NullError()
ENDIF
SELF:_value := RuntimeState.WinEncoding:GetBytes(s)
PRIVATE STATIC METHOD NullError() AS Error
VAR err := Error{ArgumentException{}}
err:Gencode := Gencode.EG_ARG
err:ArgNum := 1
err:FuncSym := "Binary.ctor"
err:Description := "Argument cannot be null"
err:Args := <OBJECT> {NULL}
RETURN err
PRIVATE CONSTRUCTOR( lhs AS BYTE[], rhs AS BYTE[])
VAR len := lhs:Length + rhs:Length
VAR result := BYTE[]{len}
System.Array.Copy(lhs, result, lhs:Length)
System.Array.Copy(rhs, 0, result,lhs:Length, rhs:Length)
_value := result
#endregion
#region Properties
/// <summary>Binary value as array of Bytes</summary>
PROPERTY @@Value AS BYTE[] GET IIF (_value == NULL, NULL, (BYTE[]) _value:Clone())
PROPERTY Length AS LONG GET iif(_value == NULL, 0, _value:Length)
#endregion
#region Equality Operators
/// <inheritdoc />
OVERRIDE METHOD Equals(rhs AS OBJECT ) AS LOGIC
LOCAL result AS LOGIC
IF rhs != NULL .AND. rhs IS __Binary
result := SELF:Equals( (__Binary) rhs)
ELSE
result := FALSE
ENDIF
RETURN result
/// <inheritdoc />
METHOD Equals(rhs AS __Binary ) AS LOGIC
IF SELF:Length != rhs:Length
RETURN FALSE
ENDIF
FOR VAR i := 0 TO SELF:Length-1
IF SELF:_value[i] != rhs:_value[i]
RETURN FALSE
ENDIF
NEXT
RETURN TRUE
/// <inheritdoc />
OVERRIDE METHOD GetHashCode() AS INT
RETURN SELF:_value:GetHashCode()
/// <exclude />
METHOD GetTypeCode() AS TypeCode
RETURN TypeCode.Object
/// <include file="RTComments.xml" path="Comments/Operator/*" />
[NODEBUG] [INLINE];
OPERATOR ==(lhs AS __Binary, rhs AS __Binary) AS LOGIC
RETURN lhs:Equals(rhs)
/// <include file="RTComments.xml" path="Comments/Operator/*" />
[NODEBUG] [INLINE];
OPERATOR !=(lhs AS __Binary, rhs AS __Binary) AS LOGIC
RETURN ! lhs:Equals(rhs)
#endregion
#region Comparison Operators
/// <include file="RTComments.xml" path="Comments/Operator/*" />
OPERATOR >(lhs AS __Binary, rhs AS __Binary) AS LOGIC
VAR len := Math.Min(lhs:Length,rhs:Length)
VAR res := RuntimeState.StringCompare(lhs:_value, rhs:_value, len)
IF res > 0
RETURN TRUE
ELSEIF res < 0
RETURN FALSE
ENDIF
RETURN lhs:Length > rhs:Length
/// <include file="RTComments.xml" path="Comments/Operator/*" />
OPERATOR <(lhs AS __Binary, rhs AS __Binary) AS LOGIC
VAR len := Math.Min(lhs:Length,rhs:Length)
VAR res := RuntimeState.StringCompare(lhs:_value, rhs:_value, len)
IF res < 0
RETURN TRUE
ELSEIF res > 0
RETURN FALSE
ENDIF
RETURN lhs:Length < rhs:Length
/// <include file="RTComments.xml" path="Comments/Operator/*" />
OPERATOR >=(lhs AS __Binary, rhs AS __Binary) AS LOGIC
VAR len := Math.Min(lhs:Length,rhs:Length)
VAR res := RuntimeState.StringCompare(lhs:_value, rhs:_value, len)
IF res > 0
RETURN TRUE
ELSEIF res < 0
RETURN FALSE
ENDIF
RETURN lhs:Length >= rhs:Length
/// <include file="RTComments.xml" path="Comments/Operator/*" />
OPERATOR <=(lhs AS __Binary, rhs AS __Binary) AS LOGIC
VAR len := Math.Min(lhs:Length,rhs:Length)
VAR res := RuntimeState.StringCompare(lhs:_value, rhs:_value, len)
IF res < 0
RETURN TRUE
ELSEIF res > 0
RETURN FALSE
ENDIF
RETURN lhs:Length <= rhs:Length
#endregion
#region Implicit Converters
/// <include file="RTComments.xml" path="Comments/Operator/*" />
[NODEBUG] [INLINE];
STATIC OPERATOR IMPLICIT(b AS BYTE[]) AS __Binary
RETURN __Binary{(BYTE[])b:Clone()}
/// <include file="RTComments.xml" path="Comments/Operator/*" />
[NODEBUG] [INLINE];
STATIC OPERATOR IMPLICIT(b AS __Binary) AS BYTE[]
RETURN b:Value
/// <include file="RTComments.xml" path="Comments/Operator/*" />
[NODEBUG] [INLINE];
STATIC OPERATOR IMPLICIT(bytes AS __Binary) AS STRING
RETURN RuntimeState.WinEncoding:GetString(bytes:_value)
/// <include file="RTComments.xml" path="Comments/Operator/*" />
[NODEBUG] [INLINE];
STATIC OPERATOR IMPLICIT(s AS STRING) AS __Binary
RETURN __Binary{ s }
#endregion
#region Numeric Operators
/// <include file="RTComments.xml" path="Comments/Operator/*" />
OPERATOR+(lhs AS __Binary, rhs AS __Binary) AS __Binary
RETURN __Binary{lhs:_value, rhs:_value}
/// <include file="RTComments.xml" path="Comments/Operator/*" />
OPERATOR+(lhs AS __Binary, rhs AS STRING) AS __Binary
RETURN __Binary{lhs:_value, RuntimeState.WinEncoding:GetBytes(rhs)}
/// <include file="RTComments.xml" path="Comments/Operator/*" />
OPERATOR+(lhs AS STRING, rhs AS __Binary) AS STRING
VAR sb := StringBuilder{}
sb:Append(lhs)
sb:Append(RuntimeState.WinEncoding:GetString(rhs))
RETURN sb:ToString()
#endregion
#region Unary Operators
#endregion
#region Add and Subtract
/// <exclude />
METHOD Add(rhs AS __Binary) AS __Binary
RETURN SELF + rhs
/// <inheritdoc />
PUBLIC METHOD CompareTo(rhs AS __Binary) AS INT
VAR len := Math.Min(SELF:Length,rhs:Length)
FOR VAR i := 0 TO len-1
IF SELF:_value[i] > rhs:_value[i]
RETURN 1
ELSEIF SELF:_value[i] < rhs:_value[i]
RETURN -1
ENDIF
NEXT
IF SELF:Length > rhs:Length
RETURN 1
ELSEIF SELF:Length < rhs:Length
RETURN -1
ENDIF
RETURN 0
/// <inheritdoc />
PUBLIC METHOD CompareTo(rhs AS OBJECT) AS INT
RETURN SELF:CompareTo( (__Binary) rhs)
#endregion
#region IFormattable
/// <inheritdoc />
PUBLIC OVERRIDE METHOD ToString() AS STRING
RETURN SELF:ToString("")
/// <inheritdoc cref="System.Double.ToString"/>
PUBLIC METHOD ToString(sFormat AS STRING) AS STRING
IF sFormat == "G"
RETURN RuntimeState.WinEncoding:GetString(SELF:_value)
ENDIF
VAR sb := StringBuilder{}
sb:Append("0h")
FOREACH VAR b IN SELF:_value
sb:Append(b:ToString("X2"))
NEXT
RETURN sb:ToString()
/// <inheritdoc />
PUBLIC METHOD ToString(format AS STRING, provider AS System.IFormatProvider) AS STRING
RETURN SELF:ToString(format)
#endregion
INTERNAL METHOD ToDebugString() AS STRING
IF _value == NULL
RETURN "<uninitialized>"
ENDIF
RETURN SELF:ToString("")
#region ISerializable
/// <inheritdoc/>
PUBLIC METHOD GetObjectData(info AS SerializationInfo, context AS StreamingContext) AS VOID
IF info == NULL
THROW System.ArgumentException{"info"}
ENDIF
info:AddValue("Value", SELF:ToString(""))
RETURN
/// <include file="RTComments.xml" path="Comments/SerializeConstructor/*" />
CONSTRUCTOR (info AS SerializationInfo, context AS StreamingContext)
IF info == NULL
THROW System.ArgumentException{"info"}
ENDIF
_value := NULL
VAR s := info:GetString("Value")
IF s:ToLower():StartsWith("0h")
_value := BYTE[]{(s:Length -2)/2} // subtract 2 for 0h
LOCAL current := 0 AS INT
FOR VAR i := 2 TO s:Length-1 STEP 2
VAR nibble := s:Substring(i,2)
_value[current] := Val("0x"+nibble)
current += 1
NEXT
ENDIF
#endregion
/*
#region IConvertible
// forward most methods to the DateTime class so there will
// be a proper (localized) error message
/// <inheritdoc />
METHOD IConvertible.ToBoolean(provider AS System.IFormatProvider) AS LOGIC
THROW NotImplementedException{}
/// <inheritdoc />
METHOD IConvertible.ToByte(provider AS System.IFormatProvider) AS BYTE
THROW NotImplementedException{}
/// <inheritdoc />
METHOD IConvertible.ToChar(provider AS System.IFormatProvider) AS CHAR
THROW NotImplementedException{}
/// <inheritdoc />
METHOD IConvertible.ToDateTime(provider AS System.IFormatProvider) AS System.DateTime
THROW NotImplementedException{}
/// <inheritdoc />
METHOD IConvertible.ToDecimal(provider AS System.IFormatProvider) AS DECIMAL
THROW NotImplementedException{}
/// <inheritdoc />
METHOD IConvertible.ToDouble(provider AS System.IFormatProvider) AS REAL8
THROW NotImplementedException{}
/// <inheritdoc />
METHOD IConvertible.ToInt16(provider AS System.IFormatProvider) AS SHORT
THROW NotImplementedException{}
/// <inheritdoc />
METHOD IConvertible.ToInt32(provider AS System.IFormatProvider) AS LONG
THROW NotImplementedException{}
/// <inheritdoc />
METHOD IConvertible.ToInt64(provider AS System.IFormatProvider) AS INT64
THROW NotImplementedException{}
/// <inheritdoc />
METHOD IConvertible.ToSByte(provider AS System.IFormatProvider) AS SByte
THROW NotImplementedException{}
/// <inheritdoc />
METHOD IConvertible.ToSingle(provider AS System.IFormatProvider) AS REAL4
THROW NotImplementedException{}
/// <inheritdoc />
METHOD IConvertible.ToUInt16(provider AS System.IFormatProvider) AS WORD
THROW NotImplementedException{}
/// <inheritdoc />
METHOD IConvertible.ToUInt32(provider AS System.IFormatProvider) AS DWORD
THROW NotImplementedException{}
/// <inheritdoc />
METHOD IConvertible.ToUInt64(provider AS System.IFormatProvider) AS UINT64
THROW NotImplementedException{}
METHOD IConvertible.ToType(conversionType AS System.Type, provider AS System.IFormatProvider) AS OBJECT
IF conversionType == TYPEOF(STRING)
RETURN SELF:ToString("")
ENDIF
THROW NotImplementedException{}
METHOD IConvertible.ToString(provider AS System.IFormatProvider) AS STRING
RETURN SELF:ToString("")
#endregion
*/
END STRUCTURE
END NAMESPACE