File: Binary.k

package info (click to toggle)
kaya 0.4.2-4
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 4,448 kB
  • ctags: 1,694
  • sloc: cpp: 9,536; haskell: 7,461; sh: 3,013; yacc: 910; makefile: 816; perl: 90
file content (307 lines) | stat: -rw-r--r-- 14,862 bytes parent folder | download
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
/** -*-C-*-ish
    Kaya standard library
    Copyright (C) 2004, 2005 Edwin Brady

    This file is distributed under the terms of the GNU Lesser General
    Public Licence. See COPYING for licence.
*/
"<summary>Manipulate binary data</summary>
<prose>This module contains low-level functions and data types for handling binary data. These functions may then be used by other modules and programs to handle specific types of binary data (for example, images, compressed files, or strings containing null bytes)</prose>"
module Binary;

import public IO;
import Builtins;

%include "binary_glue.h";
%imported "binary_glue";

"<summary>Block of binary data.</summary>
<prose>This is a block of raw data. When storing or retrieving bytes, they
are treated in Kaya as <code>Int</code>s, but really they are
8 bit values. If you try to store an Int greater than 256, only the low 8 bits will be used.</prose>
<related>Created with <functionref>createBlock</functionref>.</related>
<related>Created and initialised with <functionref>createInitialisedBlock</functionref>.</related>"
abstract data Binary = Bin(Ptr bindata,Int blocksize);

"<summary>Attempt to access an offset outside a block</summary>
<prose>This Exception is thrown if you attempt to read or write past the bounds of a Binary block.</prose>
<related><dataref>Binary</dataref></related>"
Exception OffsetOutOfRange;

foreign "binary_glue.o" {
    Ptr newBlock(Int size) = newBlock;
    Void dopoke(Ptr block, Int offset, Int val) = poke;
    Int dopeek(Ptr block, Int offset) = peek;
    Void dopokeString(Ptr block, Int offset, String val) = pokestring;
    String dopeekString(Ptr block, Int offset) = peekstring;
    Ptr docopyBlock(Ptr block, Int size) = copyBlock;
    Ptr docopyChunk(Ptr block, Int offset, Int size) = copyChunk;
    [Int] dogetBlockData(Ptr block, Int offset, Int size) = getBlockData;
    Void dosetBlockData(Ptr block, Int offset, Int size, [Int] dat)
	= setBlockData;
    Int dowriteBlock(Ptr f, Ptr block, Int size) = writeBlock;
    Ptr doreadBlock(Ptr f, a size) = readBlock;

    String b64binary(Ptr block, Int len) = b64binary;
    Ptr b64binarydec(String block, intval len) = b64binarydec;
}

"<argument name='bsize'>The size of the block. Block sizes cannot be changed once the block is created.</argument>
<summary>Create a new, uninitialised block for binary data.</summary>
<prose>Create a new, uninitialised block for binary data. Remember to use <functionref>Builtins::byteLength</functionref> instead of <functionref>Builtins::length</functionref> if you want to store Strings in these, as you may have problems with multi-byte characters otherwise.</prose>
<prose>The uninitialised contents of this block are not guaranteed to be zeroes.</prose>
<related><dataref>Binary</dataref></related>"
public Binary createBlock(Int bsize)
{
    return Bin(newBlock(bsize),bsize);
}

"<argument name='ptr'>A pointer to a foreign structure.</argument>
<argument name='bsize'>The size of the structure in bytes.</argument>
<summary>Create a new and initialised block for binary data.</summary>
<prose>Create a new and initialised block for binary data. Note that the contents of the block <emphasis>are</emphasis> the structure, not a copy of it, so any writes made here will affect the foreign structure.</prose>
<related><dataref>Binary</dataref></related>"
public Binary createInitialisedBlock(Ptr ptr,Int bsize)
{
    return Bin(ptr,bsize);
}

"<argument name='b'>The Binary block</argument>
<summary>Get the size of a block</summary>
<prose>Get the size of a binary block in bytes.</prose>
<related><dataref>Binary</dataref></related>"
public Int blockSize(Binary b)
{
    return b.blocksize;
}

"<argument name='b'>The Binary block</argument>
<summary>Get a foreign pointer to Binary data</summary>
<prose>Get a foreign pointer to Binary data to pass to a foreign function call.</prose>
<related><dataref>Binary</dataref></related>"
public Ptr blockData(Binary b)
{
    return b.bindata;
}

"<argument name='block'>The binary block</argument>
<argument name='offset'>The location to write to (starting from zero)</argument>
<argument name='val'>The byte value to write.</argument>
<summary>Modify binary data.</summary>
<prose>Poke the value <variable>val</variable> into the offset <variable>offset</variable>. An <exceptref>OffsetOutOfRange</exceptref> exception will be thrown 
if it attempts to access a value outside the block.</prose>
<related><dataref>Binary</dataref></related>
<related><functionref>peek</functionref></related>
<related><functionref>pokeString</functionref></related>
<related><functionref>setBlockData</functionref></related>"
public Void poke(var Binary block, Int offset, Int val)
{
    if (offset<0 || offset>=block.blocksize) {
	throw(OffsetOutOfRange);
    }
    dopoke(block.bindata,offset,val);
}

"<argument name='block'>The binary block</argument>
<argument name='offset'>The location to read from (starting from zero)</argument>
<summary>Query binary data.</summary>
<prose>Retrieve the byte at offset <variable>offset</variable>. An <exceptref>OffsetOutOfRange</exceptref> exception will be thrown 
if it attempts to access a value outside the block.</prose>
<related><dataref>Binary</dataref></related>
<related><functionref>array</functionref></related>
<related><functionref>getBlockChunk</functionref></related>
<related><functionref>peekString</functionref></related>
<related><functionref>poke</functionref></related>"
public Int peek(Binary block,Int offset)
{
    if (offset<0 || offset>=block.blocksize) {
	throw(OffsetOutOfRange);
    }
    return dopeek(block.bindata,offset);
}

"<argument name='block'>The binary block</argument>
<argument name='offset'>The location to write to (starting from zero)</argument>
<argument name='val'>The String to write.</argument>
<summary>Write a String of binary data.</summary>
<prose>Poke the string <variable>val</variable> into the block, starting at offset <variable>offset</variable>. An <exceptref>OffsetOutOfRange</exceptref> exception will be thrown if it attempts to access a value outside the block. Note that the String will be stored in the block in UTF-8 encoding, not as raw Kaya chars, so you need to use <functionref>Builtins::byteLength</functionref> to determine how much space you need.</prose>
<related><dataref>Binary</dataref></related>
<related><functionref>Builtins::byteLength</functionref></related>
<related><functionref>peekString</functionref></related>
<related><functionref>poke</functionref></related>
<related><functionref>setBlockData</functionref></related>"
public Void pokeString(var Binary block, Int offset, String val)
{
    if (offset<0 || offset>=(block.blocksize-byteLength(val))) {
	throw(OffsetOutOfRange);
    }
    dopokeString(block.bindata,offset,val);
}

"<argument name='block'>The binary block</argument>
<argument name='offset'>The location to read from (starting from zero)</argument>
<summary>Read a String from binary data.</summary>
<prose>Peek at the string <variable>val</variable> starting at offset <variable>offset</variable>. An <exceptref>OffsetOutOfRange</exceptref> exception will be thrown if it attempts to access a value outside the block. Note that Kaya assumes the String is stored in the block in UTF-8 encoding, with null-termination.</prose>
<related><dataref>Binary</dataref></related>
<related><functionref>array</functionref></related>
<related><functionref>getBlockChunk</functionref></related>
<related><functionref>peek</functionref></related>
<related><functionref>pokeString</functionref></related>"
public String peekString(Binary block,Int offset)
{
    if (offset<0 || offset>=block.blocksize) {
	throw(OffsetOutOfRange);
    }
    return dopeekString(block.bindata,offset);
}

"<argument name='block'>The block of data</argument>
<summary>Copy a block of data.</summary>
<prose>Creates a new block with identical size and contents to <variable>block</variable>. This can be used to allow editing of data from a block created with <functionref>createInitialisedBlock</functionref>, without altering the foreign structure itself.</prose>
<example>cblock = createInitialisedBlock(ptr,len);
kblock = copyBlock(cblock);</example>
<related><dataref>Binary</dataref></related>
<related><functionref>copyChunk</functionref></related>
<related><functionref>createInitialisedBlock</functionref></related>"
public Binary copyBlock(Binary block)
{
    return Bin(docopyBlock(block.bindata,block.blocksize),
	       block.blocksize);
}

"<argument name='block'>The block of data</argument>
<argument name='offset'>The initial offset</argument>
<argument name='bsize'>The size of new block to create.</argument>
<summary>Copy a sub-block.</summary>
<prose>Creates a new block from the contents of the original starting at <variable>offset</variable> with a length of <variable>bsize</variable> bytes. An <exceptref>OffsetOutOfRange</exceptref> exception will be thrown if it attempts to access a value outside the block.</prose>
<related><dataref>Binary</dataref></related>
<related><functionref>copyBlock</functionref></related>
<related><functionref>getBlockChunk</functionref></related>"
public Binary copyChunk(Binary block, Int offset, Int bsize)
{
    if (offset<0 || (offset+bsize)>=block.blocksize) {
	throw(OffsetOutOfRange);
    }
    return Bin(docopyChunk(block.bindata,offset,bsize),bsize);
}

"<argument name='block'>The binary block</argument>
<argument name='offset'>The offset to start at (zero-indexed)</argument>
<argument name='bsize'>The length of chunk to read</argument>
<summary>Return a chunk from a block as an array.</summary>
<prose>Return a chunk from a block as an array. Throws an <exceptref>OffsetOutOfRange</exceptref> Exception if it attempts to access a value outside the block.</prose>
<related><dataref>Binary</dataref></related>
<related><functionref>array</functionref></related>
<related><functionref>copyChunk</functionref></related>
<related><functionref>peek</functionref></related>
<related><functionref>peekString</functionref></related>
<related><functionref>setBlockData</functionref></related>"
public [Int] getBlockChunk(Binary block, Int offset, Int bsize)
{
    if (offset<0 || (offset+bsize)>=block.blocksize) {
	throw(OffsetOutOfRange);
    }
    return dogetBlockData(block.bindata,offset,bsize);
}

"<argument name='block'>The binary block</argument>
<summary>Return a block as an array.</summary>
<prose>Return a block as an array of <code>Int</code>s.</prose>
<related><dataref>Binary</dataref></related>
<related><functionref>copyBlock</functionref></related>
<related><functionref>getBlockChunk</functionref></related>
<related><functionref>peek</functionref></related>
<related><functionref>peekString</functionref></related>
<related><functionref>setBlockData</functionref></related>"
public [Int] array(Binary block)
{
    return dogetBlockData(block.bindata,0,block.blocksize);
}

"<argument name='block'>The binary block</argument>
<argument name='offset'>The offset to start at (zero-indexed)</argument>
<argument name='bdata'>The data to write, as an array of <code>Int</code>s</argument>
<summary>Set the contents of a block.</summary>
<prose>Set the contents of (part of) a block from an array. An <exceptref>OffsetOutOfRange</exceptref> Exception will be thrown if this would cause a write outside the bounds of the block. The following bits of code are equivalent:</prose>
<example>setBlockData(block,offset,bdata);
// is equivalent to
for byte@idx in bdata {
    poke(block,offset+idx,byte);
}</example>
<prose>However, <code>setBlockData</code> is more efficient and checks bounds before any data is written - the above for loop could write partial data if <code>offset+idx</code> was greater than <code>blockSize(block)</code>.</prose>
<related><dataref>Binary</dataref></related>
<related><functionref>array</functionref></related>
<related><functionref>copyBlock</functionref></related>
<related><functionref>getBlockChunk</functionref></related>
<related><functionref>poke</functionref></related>
<related><functionref>pokeString</functionref></related>"
public Void setBlockData(var Binary block, Int offset, [Int] bdata)
{
    bsize = size(bdata);
    if (offset<0 || (offset+bsize)>=block.blocksize) {
	throw(OffsetOutOfRange);
    }
    dosetBlockData(block.bindata,offset,bsize,bdata);
}

"<argument name='h'>A file handle to write to</argument>
<argument name='block'>The binary data</argument>
<summary>Write a block to a file.</summary>
<prose>Write the contents of a Binary block to a file. The file must already be open and writable, of course. A <exceptref>IO::FileError</exceptref> Exception will be thrown if the block was not written in its entirety.</prose>
<related><dataref>Binary</dataref></related>
<related><moduleref>IO</moduleref></related>
<related><functionref>readBlock</functionref></related>"
public Void writeBlock(File h,Binary block)
{
    writeCheck(h);
    written = dowriteBlock(ptr(h),block.bindata,block.blocksize);
    if (written<block.blocksize) {
	throw(FileError);
    }
}

"<argument name='h'>A file handle to read from</argument>
<argument name='bsize'>The maximum number of bytes to read</argument>
<summary>Read a block from a file.</summary>
<prose>Creates a block of size <variable>bsize</variable> and reads data into it.
If there is less data to read than <variable>bsize</variable>, the block will contain as much data as could be read, and the <functionref>blockSize</functionref> function will return the size of the data that was read. Naturally, the file handle must be valid and readable.</prose>
<related><dataref>Binary</dataref></related>
<related><moduleref>IO</moduleref></related>
<related><functionref>writeBlock</functionref></related>"
public Binary readBlock(File h,Int bsize)
{
    val = subvert(bsize);
    readCheck(h);
    bdata = doreadBlock(ptr(h),val);
    return Bin(bdata,subvert(val));
}

"<argument name='block'>The block to encode</argument>
<summary>base64 encode a block</summary>
<prose>Returns a String containing the base64-encoded contents of the Binary block.</prose>
<related><dataref>Binary</dataref></related>
<related><functionref>base64Decode</functionref></related>
<related><functionref>Strings::base64Encode</functionref></related>"
public String base64Encode(Binary block)
{
    return b64binary(block.bindata, block.blocksize);
}

"<argument name='block'>The String to decode</argument>
<summary>base64 decode a String</summary>
<prose>Returns a binary Block from base64-decoding of the String.</prose>
<related><dataref>Binary</dataref></related>
<related><functionref>base64Encode</functionref></related>
<related><functionref>Strings::base64Decode</functionref></related>"
public Binary base64Decode(String block)
{
    len = 0;
    dec = b64binarydec(block,len);
    newptr = docopyBlock(dec, len);

    return Bin(newptr,len);
}