/* * idlsave.i - $Id$ * read IDL save files * IDL is a trademark of Reasearch Systems Incorporated (RSI) * code based on work of Craig Markwardt * http://cow.physics.wisc.edu/~craigm/idl/ */ /* ; ============== STATEMENT OF RESEARCH SYSTEMS INCORPORATED ============== ;--------------------------------------------------------------------------- ; IDL is a product of Research Systems, Inc (RSI). Use of IDL is governed ; by the IDL End User License Agreement (EULA). All IDL users are ; required to read and agree to the terms of the IDL EULA at the time ; that they install IDL. ; ; The CMSVLIB software, written by Craig Markwardt, embodies ; unpublished proprietary information about the IDL Save file ; format. Research Systems grants to the author of this software, and ; to all IDL users, a license to use and redistribute this software in ; source or binary form, subject to the following conditions: ; ; 1. The author, and any users of this software must be in full ; compliance with the IDL End User License Agreement (EULA). ; 2. Redistributions of source code must retain the complete and ; unaltered text of this notice. ; 3. Redistributions in binary form must reproduce the complete and ; unaltered text of this notice in the documentation and/or other ; materials provided with the distribution. ; 4. The name of Research Systems Inc. may not be used to endorse or ; promote this software or products derived from it without specific ; prior written permission from Research Systems, Inc. ; 5. Allowed use of this software is limited to reading and writing ; IDL variable related portions of IDL Save files. It may not be ; used as a basis for reverse engineering, or otherwise ; accessing any other portions of an IDL save file, including but ; not limited to, those portions that encode executable IDL programs. ; Such use is in violation of the IDL EULA, and will be prosecuted ; to the fullest extent possible by Research Systems, Inc. It is ; permissible to read such sections of an IDL save file for the ; sole purpose of transferring it without examination or interpretation ; to another save file. ; 6. Research Systems disclaims any responsibility for compatibility ; with this software, and reserves the right to change the IDL save ; file format in any way, at any time, including changes that would ; render this software incomplete or inoperable. ; 7. This software is not a product of Research Systems Inc. Research ; Systems Inc disclaims any responsibility for its development or ; maintenance. ; ; THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ; OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ; IN NO EVENT SHALL THE AUTHOR OR RESEARCH SYSTEMS INC BE LIABLE FOR ANY ; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ; OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ; LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ; OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ; SUCH DAMAGE. ;--------------------------------------------------------------------------- */ func idl_open (name, &commons, loud=) /* DOCUMENT f = idl_open(filename) * or f = idl_open(filename, commons) * openb for an IDL save file * optional COMMONS is returned as an array of pointers to * arrays of strings; the first string in each array is the name * of an IDL common block; the others are the names of the * variables in that common block * all variable names have been converted to lower case * loud=1 keyword reports on timestamp and other information * about the user, host, etc., stored in the save file * * floating complex data becomes an array of float with leading * dimension of 2, use f2z to recover complex * 64 bit integers become an array of long with leading dimension * of 2, use l2ll to recover single long (if sizeof(long)=8) * * SEE ALSO: openb, f2z, l2ll */ { f = open(name, "rb"); sign = array(char, 4); _read, f, 0, sign; if (anyof(sign != ['S','R','\0','\4'])) error, name+" signature not that of IDL save file"; /* Markwardt doesn't say that save file is XDR format, but seems to be */ xdr_primitives, f; /* ?? save files always big-endian, 4 byte longs ?? */ len = sizeof(f); commons = []; ncommon = 0; a64 = 0; for (addr=4 ; addr<len ;) { addr0 = addr; type = _idl_record(f, a64, addr); if (type == 6) break; addr0 += 16+a64; if (type == 10) { addr0 += 1024; date = _idl_string(f, addr0); user = _idl_string(f, addr0); host = _idl_string(f, addr0); if (loud) { write, format="Date: %s\n", date; write, format="User: %s\n", user; write, format="Host: %s\n", host; } } else if (type == 14) { sfmt = 0; _read, f, addr0, sfmt; addr0 += 4; arch = _idl_string(f, addr0); osys = _idl_string(f, addr0); ridl = _idl_string(f, addr0); if (loud) { write, format="Save: %ld\n", sfmt; write, format="Arch: %s\n", arch; write, format="OS: %s\n", osys; write, format="IDL: %s\n", ridl; } } else if (type == 13) { author = _idl_string(f, addr0); title = _idl_string(f, addr0); other = _idl_string(f, addr0); if (loud) { write, format="Author: %s\n", author; write, format="Title: %s\n", title; write, format="Other: %s\n", other; } } else if (type == 15) { write, "WARNING: "+name+" has IDL pointers"; } else if (type == 17) { if (loud) write, "64 bit addresses present"; } else if (type == 1) { nvars = 0; _read, f, addr0, nvars; addr0 += 4; if (ncommon >= numberof(commons)) grow, commons, array(pointer, max(numberof(commons), 4)); com = array(string, nvars+1); for (i=1 ; i<=nvars+1 ; i++) com(i) = _idl_string(f, addr0, 1); commons(++ncommon) = &com; com = []; } else if (type==2 || type==3) { vname = _idl_string(f, addr0, 1); if (_idl_type(f, addr0, vtype, vdims)) add_variable, f, addr0, vname, vtype, vdims; } } if (ncommon && loud) write, format="Common blocks: %ld\n", ncommon; return f; } /* record types: * 0 start_marker -- start of save file * 1 common -- common block * 2 variable * 3 system_variable * 6 end_marker -- end of save file (no more records) * 10 timestamp * 12 compiled -- IDL byte code * 13 identification -- of author * 14 version -- of IDL * 15 heap_header -- index info for heap * 16 heap_data -- heaps used for pointer data * 17 promote64 -- begin 64 bit record addresses */ func _idl_record(f, &a64, &addr) { head = array(long, 3); _read, f, addr, head; type = head(1); addr = head(2); addrlo = head(3); /* Markwardt doesn't say if promote64 record itself has 8 byte addr! */ if (!addr && addrlo) addr = addrlo; else if (a64) addr = addrlo | (addr<<32); if (type == 17) a64 = 4; return type; } func _idl_string(f, &addr, lc) { len = 0; _read, f, addr, len; addr += 4; if (len > 0) { c = array(char, len); _read, f, addr, c; addr += len; len &= 3; if (len) addr += 4-len; if (lc) { list = where((c>='A') & (c<='Z')); if (numberof(list)) c(list) |= ('A'~'a'); } } else if (len < 0) { c = []; } return string(&c); } /* data types (Sun XDR format): * 1 char * 2 short * 3 long * 4 float * 5 double * 6 fcomplex * 7 (string) * 8 (struct) * 9 complex * 10 (pointer) * 11 (object reference) * 12 ushort * 13 ulong * 14 llong (64 bit) * 15 ullong (64 bit) */ func _idl_type(f, &addr, &vtype, &vdims) { vtype = 0; _read, f, addr, vtype; addr += 4; flag = 0; _read, f, addr, flag; addr += 4; vdims = []; /* flag bit 0x10 may indicate membership in a common block */ if (flag & 0x24) { ad = array(0, 4); _read, f, addr, ad; /* ad(2) = 0x02 normally, 0x04, 0x08 observed in common block vars * 0x36 in system vars with broken dimension lists (IDL 6.0) */ if (ad(1)!=8 || (ad(2)&0x20)) { if (loud) write, "WARNING: unknown type, skipping "+vname; return 0; } ndims = 0; addr += 16; _read, f, addr, ndims; addr += 12; if (ndims<1 || ndims>10) { if (loud) write, "WARNING: bad dims, skipping "+vname; return 0; } vdims = array(0, 1+ndims); _read, f, addr, vdims; addr += 4*(vdims(1)+1); vdims(1) = ndims; if (flag & 0x20) { /* don't bother with structs for now */ if (loud) write, "WARNING: struct type, skipping "+vname; return 0; } } addr += 4; if (vtype == 1) { vtype = char; return 1; } else if (vtype==2 || vtype==12) { vtype = short; return 1; } else if (vtype==3 || vtype==13) { vtype = long; return 1; } else if (vtype == 4) { vtype = float; return 1; } else if (vtype == 5) { vtype = double; return 1; } else if (vtype == 9) { vtype = complex; return 1; } else if (vtype == 6) { /* see f2z below */ vtype = float; if (!numberof(vdims)) { vdims = [1,2]; } else { vdims = grow([vdims(1)+1],vdims); vdims(2) = 2; } return 1; } else if (vtype==14 || vtype==15) { /* see l2ll below */ vtype = long; if (!numberof(vdims)) { vdims = [1,2]; } else { vdims = grow([vdims(1)+1],vdims); vdims(2) = 2; } return 1; } return 0; } func f2z (x) /* DOCUMENT z = f2z(x) * convert 2-by-dims float or double X to complex. */ { z = x(1,..)+0.0i; z.im = x(2,..); return z; } func l2ll (x) /* DOCUMENT z = l2ll(x) * convert 2-by-dims 32 bit integer X to 64 bit integer * (only works if sizeof(long)=8) */ { return long(x(2,..)) | (long(x(1,..))<<32); }