diff --git a/Makefile b/Makefile index 1cd357f..2a61141 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,7 @@ prefix=/usr/local prefix_lib=$(prefix)/lib prefix_include=$(prefix)/include prefix_bin=$(prefix)/bin +prefix_math=$(prefix)/math prefix_doc=$(prefix)/doc .PHONY: all clean realclean install do.install @@ -68,6 +69,8 @@ do.install: lhpc-aff-config docs/aff_spec.pdf COPYRIGHT cp $$f $(prefix_doc)/$$bf; \ chmod 444 $(prefix_doc)/$$bf; \ done + mkdir -p $(prefix_math) + cp math/aff.m $(prefix_math)/aff.m lhpc-aff-config: Makefile config/$(CONFIG) aff-config.in sed -e 's?@CC@?$(install.CC)?' \ diff --git a/docs/aff_spec.pdf b/docs/aff_spec.pdf index ed3df17..affe1f5 100644 Binary files a/docs/aff_spec.pdf and b/docs/aff_spec.pdf differ diff --git a/docs/aff_spec.tex b/docs/aff_spec.tex index 7e1e00f..7b58384 100644 --- a/docs/aff_spec.tex +++ b/docs/aff_spec.tex @@ -29,6 +29,7 @@ %\newcommand{\Synopsis}{{\textbf Synopsis}\\} %\newcommand{\RetValue}{{\textbf Return value}\\} \def\FuncHead#1{\pagebreak[3]\subsubsection{\libname{#1()}}} +\def\MathFuncHead#1{\pagebreak[3]\subsubsection{\libname{#1[]}}} \def\Syn{\par\nopagebreak[4]\noindent{\bf Synopsis}\tt \everypar={\hangindent=64pt\hangafter=1 \raggedright\hspace{16pt}}\par\noindent\nopagebreak[4]} @@ -47,7 +48,7 @@ \centerline{\it Andrew~V.~Pochinsky, Sergey~N.~Syritsyn} \centerline{\it MIT CTP, Cambridge, MA} \vspace{10pt} -\centerline{November 29, 2007} +\centerline{December 4, 2007} \vspace{20pt} \noindent This document describes the AFF data storage format. @@ -188,9 +189,9 @@ \subsection{Header} \begin{tabular}{|l|c|c|} \hline & Size, bytes (V1) & Size, bytes (V2)\\ \hline\hline Signature & 32 & 32 \\ \hline +Data header & 32 & 40 \\ \hline Symbol table header & 32 & 40 \\ \hline Tree header & 32 & 40 \\ \hline -Data header & 32 & 40 \\ \hline Header MD5 sum & 16 & 16 \\ \hline\hline Total & 144 & 168 \\ \hline \end{tabular} @@ -775,6 +776,7 @@ \subsection{Treap structure} \section{MD5 sum functions} This functions implement the MD5 cryptographic checksum as described in RFC~1321. The implementation is taken from the RFC, only the naming conventions were changed to confirm to the rest of the library. +\subsection{The Interface} \FuncHead{aff\_md5\_init} {\Syn void~aff\_md5\_init (struct~AffMD5\_s~*);} @@ -788,6 +790,36 @@ \section{MD5 sum functions} {\Syn void~aff\_md5\_final (uint8\_t~[16], struct~AffMD5\_s~*);} \Desc{Produce the final value of MD5 sum.} +\newpage +\section{AFF Mathematica Interface} +By popular demand, there is also a read AFF interface for Wolfram's Mathematica. +The interface consists of the following three functions; please note, however, +that it is not as bullet-proof as the C interface---it does not do error +checking to the same extend. + +You will need to load file \ctext{\$(prefix)/math/aff.m} into Mathematica to use +the interface. +\subsection{The Interface} + +\MathFuncHead{affOpen} +{\Syn affHandle = affOpen [fileName];} +\Desc{Open \cvar{fileName} as an AFF and prepare for reading data from it.} +\RetVal{A handle to a Mathematica AFF object is returned.} + +\MathFuncHead{affGet} +{\Syn \{type, \{data, ...\}\} = affGet [affHandle, keyPath];} +\Desc{Read data stored under the \cvar{keyPath} in the AFF handle + \cvar{affHandle} which should have been previosly opened with + \ctext{affOpen[]}.} +\RetVal{If \cvar{keyPath} is not present, return \ctext{\$Failure}; otherwise, + the type of data and the data itself are returned. + The data is returned as a list of values.} + +\MathFuncHead{affClose} +{\Syn affClose [affHandle];} +\Desc{Close the file associated with \ctext{affHandle} and free all allocated +resources.} + \printindex \end{document} diff --git a/lib/aff-version.c b/lib/aff-version.c index fe35b3a..4ea5a5f 100644 --- a/lib/aff-version.c +++ b/lib/aff-version.c @@ -11,6 +11,7 @@ * 2007/11/29 avp -- final rc2 for v 2.0.0 * 2007/11/29 avp -- final rc3 for v 2.0.0 * 2007/11/30 avp -- v 2.0.0 + * 2007/12/04 avp -- v 2.0.2 */ const char * aff_version(void) diff --git a/lib/raff-init.c b/lib/raff-init.c index a6982cd..7179a13 100644 --- a/lib/raff-init.c +++ b/lib/raff-init.c @@ -185,13 +185,6 @@ aff_reader(const char *file_name) uint32_t byte_count; uint64_t tree_size; uint32_t sig_size; -#if 0 - uint32_t data; - int size; - int sb_size; - int sb_used; - uint64_t string_size; -#endif if (aff == 0) return 0; @@ -227,58 +220,6 @@ aff_reader(const char *file_name) aff->error = "Bad AFF header"; goto error; } -#if 0 - if (fread(buf, sizeof (buf), 1, aff->file) != 1) { - aff->error = "Reading AFF header failed"; - goto error; - } - aff_md5_init(&md5); - aff_md5_update(&md5, buf, sizeof (buf) - 16); - aff_md5_final(md5_read, &md5); - if (memcmp(md5_read, buf + sizeof (buf) - 16, 16) != 0) { - aff->error = "AFF header failed checksum"; - goto error; - } - - /* NB: This should match writer_fini() */ - buf[sizeof(buf) - 1] = 0; /* Paranoia? I don't think so */ - if (strcmp((const char *)buf, (const char *)aff_signature) != 0) { - aff->error = "AFF signature mismatch"; - goto error; - } - size = strlen((const char *)aff_signature) + 1; - if (buf[size] != sizeof (double) * CHAR_BIT) { - aff->error = "AFF size if double mismatch"; - goto error; - } - if (buf[size+1] != FLT_RADIX || FLT_RADIX != 2) { - aff->error = "AFF double radix mismatch"; - goto error; - } - if (buf[size+2] != DBL_MANT_DIG) { - aff->error = "AFF double mantissa size mismatch"; - goto error; - } - if (aff_decode_u32(&data, buf + size + 3, 4) == 0) { - aff->error = "AFF error decoding double exponent sizes"; - goto error; - } - if ((data >> 16 != DBL_MAX_EXP) || ((data & 0xffff) != (- DBL_MIN_EXP))) { - aff->error = "AFF exponent limits mismatch"; - goto error; - } - if (aff_decode_u32(&data, buf + size + 7, 4) == 0 || - data != AFF_HEADER_SIZE) { - aff->error = "AFF header size check failed"; - goto error; - } - unpack(aff, &aff->data_hdr, buf, size+11, "data header unpack failed"); - unpack(aff, &aff->stable_hdr, buf, size+43, "stable header unpack failed"); - unpack(aff, &aff->tree_hdr, buf, size+75, "tree header unpack failed"); - - if (aff->error) - goto error; -#endif /* load the stable */ rec_count = aff->stable_hdr.records; /* = 0 in V1 */ diff --git a/math/aff.m b/math/aff.m index 0c45608..891eb03 100644 --- a/math/aff.m +++ b/math/aff.m @@ -11,7 +11,7 @@ tbOff, tbSize, tbCount, affSym, nodeTypes, affRoot, affNodes, affName, affOffset, affSize, affType, affChildren, - affXGet, affXClose, + affXGet, affXClose, affXFormat, name, type, offset, size, children}, affOpened = False; aff = OpenRead[fileName, BinaryFormat -> True]; @@ -80,36 +80,36 @@ root = Map[Function[c,affName[[c]]->affNodes[[c]]], affRoot]; - affXGet[aO_, path_String] := - Module[{t,o,s,d,fmt,lookup}, - If [affOpened == False, Return[$Failed]]; - lookup = Module[{ks, d, ch}, - ks = StringSplit[path, "/"]; - If [ks == {}, Return[$Failed]]; - d = First[ks] /. root; - If [d == First[ks], Return[$Failed]]; - For [ks = Rest[ks], - ks != {}, - ch = children /. d; - If [ch == children, Return[$Failed]]; - d = First[ks] /. ch; - ks = Rest[ks]]; - If [ListQ[d], {type/.d, offset/.d, size/.d}, - Return[$Failed]]]; - If [lookup == $Failed, Return [$Failed]]; - {t, o, s} = lookup; - fmt = Switch[t, - "void", Return[{t,0,{}}], - "char", "Character8", - "int", "Integer32", - "double", "Real64", - "complex", "Complex128", - _, Return[$Failed]]; - SetStreamPosition[aff, o]; - d = BinaryReadList[aff, fmt, s, ByteOrdering -> 1]; - {t, d}]; + affXGet[path_String] := + Module[{t,o,s,d,fmt,lookup}, + If [affOpened == False, Return[$Failed]]; + lookup = Module[{ks, d, ch}, + ks = StringSplit[path, "/"]; + If [ks == {}, Return[$Failed]]; + d = First[ks] /. root; + If [d == First[ks], Return[$Failed]]; + For [ks = Rest[ks], + ks != {}, + ch = children /. d; + If [ch == children, Return[$Failed]]; + d = First[ks] /. ch; + ks = Rest[ks]]; + If [ListQ[d], {type/.d, offset/.d, size/.d}, + Return[$Failed]]]; + If [lookup == $Failed, Return [$Failed]]; + {t, o, s} = lookup; + fmt = Switch[t, + "void", Return[{t,0,{}}], + "char", "Character8", + "int", "Integer32", + "double", "Real64", + "complex", "Complex128", + _, Return[$Failed]]; + SetStreamPosition[aff, o]; + d = BinaryReadList[aff, fmt, s, ByteOrdering -> 1]; + {t, d}]; - affXClose[aO_] := + affXClose[] := Module[{}, If [affOpened == False, Return[]]; affOpened = False; @@ -137,8 +137,15 @@ affChildren =. ; affXGet =.; affXClose =. ;]; + affXFormat[] := + Module[{}, + If [affOpened, StringJoin["affObject[\"", fileName, "\"]"], + "affObject[CLOSED]"]]; affOpened = True; - { affXGet, affXClose }]; + affObject[fileName, affXGet, affXClose, affXFormat]]; + +affGet[affObject[fn_,get_,cl_,fmt_], path_String] := get[path]; +affClose[affObject[fn_,get_,cl_,fmt_]] := cl[]; -affGet[aff_, path_String] := aff[[1]][aff, path]; -affClose[aff_] := aff[[2]][aff]; +(* Nice print format for affObjects *) +Format[affObject[fn_,a_,b_,fmt_]] := fmt[];