cmsv_wraw.pro
7.94 KB
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
;+
; NAME:
; CMSV_WRAW
;
; AUTHOR:
; Craig B. Markwardt, NASA/GSFC Code 662, Greenbelt, MD 20770
; craigm@lheamail.gsfc.nasa.gov
;
; PURPOSE:
; Write raw SAVE data to output block
;
; CALLING SEQUENCE:
; CMSV_WRAW, BLOCK, POINTER, DATA, UNIT=UNIT, $
; STRING=STRING, LONG=LONG, BYTE=BYTE, TYPE=TYPE, $
; OFFSET=OFFSET, STATUS=STATUS, ERRMSG=ERRMSG
;
; DESCRIPTION:
;
; This procedure writes raw integer or string data to an IDL SAVE
; block in memory. This is the lowest level writing function in the
; library, intended for developers who are investigating new and
; existing SAVE file formats.
;
; The data to be written is specified by the DATA parameter. The
; data must be of type BYTE, LONG or STRING, and the type is
; determined automatically from the data itself. [ The mnemonic
; STRING LONG and BYTE keywords are accepted for programming clarity
; but ignored. ]
;
; This procedure accepts but currently ignores the UNIT keyword. It
; is the caller's responsibility to write the BLOCK data to disk
; when appropriate.
;
; ==================================================================
; Research Systems, Inc. has issued a separate license intended
; to resolve any potential conflict between this software and the
; IDL End User License Agreement. The text of that license
; can be found in the file LICENSE.RSI, included with this
; software library.
; ==================================================================
;
;
; BLOCK, POINTER, OFFSET
;
; This procedure writes data to a byte array only. The intent is
; for users to accumulate a significant amount of data in a BLOCK
; and then write it out with a single call to WRITEU. Users should
; be aware that the block can be larger than the buffered data, so
; they should use something like the following:
;
; WRITEU, UNIT, BLOCK(0:POINTER-1)
;
; When library routines do indeed write buffered BLOCK data to disk,
; they will appropriately reset the BLOCK and POINTER. Namely,
; BLOCK will be reset to empty, and POINTER will be reset to zero.
; OFFSET will be advanced the according number of bytes.
;
; The terminology is as follows: BLOCK is a byte array which
; represents a portion of, or an entire, IDL SAVE file. The block
; may be a cached portion of an on-disk file, or an entire in-memory
; SAVE file. POINTER is the current file pointer within BLOCK
; (i.e., the next byte to be written is BLOCK[POINTER]). Hence, a
; POINTER value of 0 refers to the start of the block. OFFSET is
; the file offset of the 0th byte of BLOCK; thus "POINT_LUN,
; OFFSET+POINTER" should point to the same byte as BLOCK[POINTER].
; The following diagram shows the meanings for BLOCK, POINTER and
; OFFSET schematically:
;
;
; 0 <- OFFSET -> |
; FILE |----------------|------*--------|--------->
;
; BLOCK |------*--------|
; 0 ^ POINTER
;
;
; This procedure is part of the CMSVLIB SAVE library for IDL by
; Craig Markwardt. You must have the full CMSVLIB core package
; installed in order for this procedure to function properly.
;
;
; INPUTS:
;
; BLOCK - a byte array, a cache of the SAVE file. Users will
; usually not access this array directly. Users are advised
; to clear BLOCK after calling POINT_LUN or writing the
; block to disk.
;
; POINTER - a long integer, a pointer to the next byte to be written
; from BLOCK. CMSVLIB routines will automatically advance
; the pointer.
;
; DATA - the data to be written. Must of type STRING, BYTE or LONG.
;
;
; KEYWORDS:
;
; LONG - ignored (to be used for clarity)
; BYTE - ignored (to be used for clarity)
; STRING - ignored (to be used for clarity)
;
; UNIT - a file unit. Currently ignored.
;
; OFFSET - the file offset of byte zero of BLOCK.
; Upon output, if the file pointer is advanced, OFFSET will
; also be changed.
; (OFFSET is not currently used by this routine)
; Default: 0
;
; STATUS - upon return, this keyword will contain 1 for success and
; 0 for failure.
;
; ERRMSG - upon return with a failure, this keyword will contain the
; error condition as a string.
;
; EXAMPLE:
;
;
; SEE ALSO:
;
; CMRESTORE, SAVE, RESTORE, CMSVLIB
;
; MODIFICATION HISTORY:
; Written, 2000
; Documented, 24 Jan 2001
; Added notification about RSI License, 13 May 2002, CM
; Fixed bug in writing of empty strings, 28 Mar 2006, CM
; Fixed bug when writing strings >128 characters, 2012-04-05, CM
; NOTE: remember to modify CMSVLIB.PRO when changing library!
;
; $Id: cmsv_wraw.pro,v 1.9 2012/04/05 20:43:09 cmarkwar Exp $
;
;-
; Copyright (C) 2000-2001, 2006, 2012, Craig Markwardt
; This software is provided as is without any warranty whatsoever.
; Permission to use, copy, modify, and distribute modified or
; unmodified copies is granted, provided this copyright and disclaimer
; are included unchanged.
;-
pro cmsv_enlarge, block, pointer, nbytes, status=status, errmsg=errmsg
status = 1
diff = pointer+nbytes - n_elements(block)
if diff GT 0 then begin
if n_elements(block) GT 0 then $
block = [temporary(block), bytarr(diff + 1024L)] $
else $
block = bytarr(diff + 1024L)
endif
return
end
pro cmsv_wraw, block, pointer, value0, unit=unit, replen=replen, $
byte=byte, long=long, string=string, $
status=status, errmsg=errmsg
if n_elements(pointer) EQ 0 then pointer = 0L
sz = size(value0)
tp = sz(sz(0)+1)
if tp EQ 7 then begin ;; STRING DATA
;; STRING_DATA
;; LONG - STRLEN - string length in characters
;; BYTExSTRLEN - string characters, padded to next four-byte boundary
if n_elements(pointer) EQ 0 then pointer = 0L
;; Compute number of bytes required to store this data
replen1 = keyword_set(replen)
len = strlen(value0)
;; Length in bytes of the string header
llen = 4*(replen1*(len GT 0) + 1)
stride = 4
ntotbytes = long( total(floor((len+3)/4)*4L + llen) )
if pointer+ntotbytes GT n_elements(block) then $
cmsv_enlarge, block, pointer, ntotbytes
for i = 0L, n_elements(value0)-1 do begin
name = value0(i)
;; Add string length
hlen = len(i)
byteorder, hlen, /HTONL
block(pointer) = byte(hlen, 0, 4)
if replen1 AND hlen NE 0 then block(pointer+4) = byte(hlen, 0, 4)
pointer = pointer + stride + stride*replen1*(hlen NE 0)
if len(i) GT 0 then begin
;; Add string contents
nbytes = floor((len(i)+3)/4)*4L ;; Round up to next 4-bytes
block(pointer) = byte(name)
pointer = pointer + nbytes
endif
endfor
status = 1
return
endif
status = 0
nelt = n_elements(value0)
sz = size(value0)
tp = sz(sz(0)+1)
value = value0
if tp EQ 1 then begin
nbytes = 1L ;; BYTE DATA
endif else if tp EQ 3 then begin
nbytes = 4L ;; LONG DATA
endif else begin
status = 0
errmsg = 'ERROR: CMSV_WRAW: data must byte BYTE, LONG or STRING'
return
endelse
ntotbytes = nbytes * nelt
if pointer+ntotbytes GT n_elements(block) then $
cmsv_enlarge, block, pointer, ntotbytes
common cmsv_conv_common, lendian
if n_elements(lendian) EQ 0 then begin
;; Little-endian?
lendian = (long(['01'xb,'02'xb,'03'xb,'04'xb],0,1))(0) NE '01020304'xl
endif
;; Convert values to net order from host endianness
case nbytes of
; 1: dummy = 1 ; byte
; 2: byteorder, value, /HTONS ; int
4: byteorder, value, /HTONL ; long
; 8: if lendian then byteorder, value, /L64SWAP ; long64
else:
endcase
block(pointer) = byte(temporary(value), 0, ntotbytes)
pointer = pointer + ntotbytes
status = 1
return
end