RFC 1014
XDR: External Data Representation standard
Network Working Group Sun Microsystems, Inc. π Request for Comments: 1014 June 1987 β¨
XDR: External Data Representation Standard π
Okay bestie, this is the RFC that introduced XDR (External Data Representation), and it was written by folks at Sun Microsystems, Inc. back in June 1987 πΈ It's an RFC, so it's a proposal the Internet can consider, and the Status section says anyone can distribute it freely π Nothing here obsoletes or updates another document, so it's just the OG, no cap π
STATUS OF THIS MEMO β¨
Okay so this part is basically the disclaimer π Sun and some other folks were already using this standard, and they wanted to propose it to the Internet community for consideration π«Ά Distribution of this memo is unlimited, so share it with everyone you know π¦
1. INTRODUCTION π§
Okay so XDR is a standard for describing and encoding data π It's lowkey iconic for moving data between totally different computer architectures, and it was used to communicate between machines as different as the SUN WORKSTATION*, VAX*, IBM-PC*, and Cray* π₯ Like, that's a whole lineup of main character computers π
XDR fits into the ISO presentation layer, and it's roughly analogous in purpose to X.409, which is the ISO Abstract Syntax Notation π The big difference is that XDR uses implicit typing, while X.409 uses explicit typing π«Ά
XDR also has its own language for describing data formats π Important note: this language can ONLY be used to describe data, and it is NOT a programming language π It lets you describe intricate data formats in a concise way, which is way better than drawing graphical representations, because those get incomprehensible once things get complex π The XDR language is similar to the C language [1], just like Courier [4] is similar to Mesa β¨ Protocols like Sun RPC (Remote Procedure Call) and NFS* (Network File System) use XDR to describe the format of their data π
The XDR standard assumes that bytes (or octets) are portable, where a byte is defined as 8 bits of data π¦ A given hardware device should encode the bytes onto the various media so that other hardware devices can decode them without losing meaning π For example, the Ethernet* standard suggests that bytes be encoded in "little-endian" style [2], or least significant bit first π
2. BASIC BLOCK SIZE π
The representation of all items requires a multiple of four bytes (or 32 bits) of data π The bytes are numbered 0 through n-1 πΈ They're read or written to some byte stream so that byte m always comes before byte m+1 β¨ If the n bytes needed to hold the data aren't a multiple of four, then the n bytes get followed by enough (0 to 3) residual zero bytes, r, to make the total byte count a multiple of 4 π«Ά
We're including the familiar graphic box notation just for illustration and comparison π¦ In most illustrations, each box (with a plus sign at the 4 corners and vertical bars and dashes) is a byte π Ellipses (...) between boxes mean zero or more additional bytes π§
+--------+--------+...+--------+--------+...+--------+
| byte 0 | byte 1 |...|byte n-1| 0 |...| 0 | BLOCK
+--------+--------+...+--------+--------+...+--------+
|<-----------n bytes---------->|<------r bytes------>|
|<-----------n+r (where (n+r) mod 4 = 0)>----------->|
3. XDR DATA TYPES π
Each section that follows describes a data type defined in the XDR standard, shows how it's declared in the language, and includes a graphic illustration of its encoding π
For each data type, we show a general paradigm declaration π Quick heads up: angle brackets (< and >) denote variable-length sequences of data, and square brackets ([ and ]) denote fixed-length sequences of data π "n", "m" and "r" denote integers β¨ For the full language specification and more formal definitions of terms like "identifier" and "declaration", check out section 5: "The XDR Language Specification" π«Ά For some data types, more specific examples are included, and there's a more extensive example of a data description in section 6: "An Example of an XDR Data Description" π¦
3.1 Integer πΈ
An XDR signed integer is a 32-bit datum that encodes an integer in the range [-2147483648,2147483647] π It's represented in two's complement notation π§ The most and least significant bytes are 0 and 3, respectively π₯ Integers are declared like this:
int identifier;
(MSB) (LSB)
+-------+-------+-------+-------+
|byte 0 |byte 1 |byte 2 |byte 3 | INTEGER
+-------+-------+-------+-------+
<------------32 bits------------>
3.2. Unsigned Integer π
An XDR unsigned integer is a 32-bit datum that encodes a nonnegative integer in the range [0,4294967295] β¨ It's represented by an unsigned binary number whose most and least significant bytes are 0 and 3, respectively π An unsigned integer is declared like this:
unsigned int identifier;
(MSB) (LSB)
+-------+-------+-------+-------+
|byte 0 |byte 1 |byte 2 |byte 3 | UNSIGNED INTEGER
+-------+-------+-------+-------+
<------------32 bits------------>
3.3 Enumeration π¦
Enumerations have the same representation as signed integers π They're handy for describing subsets of the integers π Enumerated data is declared like this:
enum { name-identifier = constant, ... } identifier;
For example, the three colors red, yellow, and blue could be described by an enumerated type πΈ
enum { RED = 2, YELLOW = 3, BLUE = 5 } colors;
It is an error to encode as an enum any integer other than those that have been given assignments in the enum declaration. π¨
3.4 Boolean π
Booleans are important enough, and they show up often enough, to get their own explicit type in the standard π«Ά Booleans are declared like this:
bool identifier;
This is equivalent to:
enum { FALSE = 0, TRUE = 1 } identifier;
3.5 Hyper Integer and Unsigned Hyper Integer β¨
The standard also defines 64-bit (8-byte) numbers called hyper integer and unsigned hyper integer π Their representations are the obvious extensions of integer and unsigned integer from above π§ They're represented in two's complement notation π The most and least significant bytes are 0 and 7, respectively π Their declarations:
hyper identifier; unsigned hyper identifier;
(MSB) (LSB)
+-------+-------+-------+-------+-------+-------+-------+-------+
|byte 0 |byte 1 |byte 2 |byte 3 |byte 4 |byte 5 |byte 6 |byte 7 |
+-------+-------+-------+-------+-------+-------+-------+-------+
<----------------------------64 bits---------------------------->
HYPER INTEGER
UNSIGNED HYPER INTEGER
3.6 Floating-point π₯
The standard defines the floating-point data type "float" (32 bits or 4 bytes) π The encoding used is the IEEE standard for normalized single-precision floating-point numbers [3] πΈ Three fields describe the single-precision floating-point number π«Ά
- S: The sign of the number. Values 0 and 1 represent positive and negative, respectively. One bit. π
- E: The exponent of the number, base 2. 8 bits are devoted to this field. The exponent is biased by 127. π¦
- F: The fractional part of the number's mantissa, base 2. 23 bits are devoted to this field. β¨
So the floating-point number is described by:
(-1)**S * 2**(E-Bias) * 1.F
It's declared like this:
float identifier;
+-------+-------+-------+-------+
|byte 0 |byte 1 |byte 2 |byte 3 | SINGLE-PRECISION
S| E | F | FLOATING-POINT NUMBER
+-------+-------+-------+-------+
1|<- 8 ->|<-------23 bits------>|
<------------32 bits------------>
Just like the most and least significant bytes of a number are 0 and 3, the most and least significant bits of a single-precision floating-point number are 0 and 31 π§ The beginning bit (and most significant bit) offsets of S, E, and F are 0, 1, and 9, respectively π Note that these numbers refer to the mathematical positions of the bits, and NOT to their actual physical locations (which vary from medium to medium) π
The EEE specifications should be consulted concerning the encoding for signed zero, signed infinity (overflow), and denormalized numbers (underflow) [3] π According to IEEE specifications, the "NaN" (not a number) is system dependent and should not be used externally π
3.7 Double-precision Floating-point π
The standard defines the encoding for the double-precision floating-point data type "double" (64 bits or 8 bytes) πΈ The encoding used is the IEEE standard for normalized double-precision floating-point numbers [3] β¨ The standard encodes three fields that describe the double-precision floating-point number π«Ά
- S: The sign of the number. Values 0 and 1 represent positive and negative, respectively. One bit. π
- E: The exponent of the number, base 2. 11 bits are devoted to this field. The exponent is biased by 1023. π¦
- F: The fractional part of the number's mantissa, base 2. 52 bits are devoted to this field. β¨
So the floating-point number is described by:
(-1)**S * 2**(E-Bias) * 1.F
It's declared like this:
double identifier;
+------+------+------+------+------+------+------+------+
|byte 0|byte 1|byte 2|byte 3|byte 4|byte 5|byte 6|byte 7|
S| E | F |
+------+------+------+------+------+------+------+------+
1|<--11-->|<-----------------52 bits------------------->|
<-----------------------64 bits------------------------->
DOUBLE-PRECISION FLOATING-POINT
Just like the most and least significant bytes of a number are 0 and 3, the most and least significant bits of a double-precision floating-point number are 0 and 63 π§ The beginning bit (and most significant bit) offsets of S, E, and F are 0, 1, and 12, respectively π Note that these numbers refer to the mathematical positions of the bits, and NOT to their actual physical locations (which vary from medium to medium) π
The IEEE specifications should be consulted concerning the encoding for signed zero, signed infinity (overflow), and denormalized numbers (underflow) [3] π According to IEEE specifications, the "NaN" (not a number) is system dependent and should not be used externally π
3.8 Fixed-length Opaque Data π¦
Sometimes fixed-length uninterpreted data needs to be passed among machines π This data is called "opaque" and is declared like this:
opaque identifier[n];
where the constant n is the (static) number of bytes needed to contain the opaque data πΈ If n isn't a multiple of four, then the n bytes get followed by enough (0 to 3) residual zero bytes, r, to make the total byte count of the opaque object a multiple of four β¨
0 1 ...
+--------+--------+...+--------+--------+...+--------+
| byte 0 | byte 1 |...|byte n-1| 0 |...| 0 |
+--------+--------+...+--------+--------+...+--------+
|<-----------n bytes---------->|<------r bytes------>|
|<-----------n+r (where (n+r) mod 4 = 0)------------>|
FIXED-LENGTH OPAQUE
That's part 1 of 4, bestie! π§ More parts are coming, so stay tuned for the rest of XDR πβ¨
3.9. Variable-length Opaque Data β¨
okay so variable-length (counted) opaque data is the flexible one π It's a sequence of n arbitrary bytes, numbered 0 through n-1. The number n gets encoded as an unsigned integer (like we talked about above), and then the n bytes come right after it.
Byte m always comes before byte m+1, and byte 0 always comes right after the length (count) π If n isn't a multiple of four, you add 0 to 3 residual zero bytes, r, so the total byte count ends up a multiple of four. Here's how you declare it:
opaque identifier<m>;
or
opaque identifier<>;
The constant m is an upper bound on how many bytes the sequence can hold. If you skip m, like in the second one, it's assumed to be (2**32) - 1, which is the max length π The constant m usually comes from a protocol spec. For example, a filing protocol might say the max data transfer size is 8192 bytes, like this:
opaque filedata<8192>;
Here's the picture of it π¦
0 1 2 3 4 5 ...
+-----+-----+-----+-----+-----+-----+...+-----+-----+...+-----+
| length n |byte0|byte1|...| n-1 | 0 |...| 0 |
+-----+-----+-----+-----+-----+-----+...+-----+-----+...+-----+
|<-------4 bytes------->|<------n bytes------>|<---r bytes--->|
|<----n+r (where (n+r) mod 4 = 0)---->|
VARIABLE-LENGTH OPAQUE
It's an error to encode a length bigger than the max in the spec π ββοΈ
3.10. String π§΅
so a string is basically the same energy as variable-length opaque data, except it's a sequence of n ASCII bytes π It's numbered 0 through n-1, the number n is encoded as an unsigned integer (again, see above), and then the n bytes follow it.
Byte m comes before byte m+1, and byte 0 always follows the string's length. If n isn't a multiple of four, you add 0 to 3 residual zero bytes, r, to get the total byte count to a multiple of four β¨ Counted byte strings get declared like this:
string object<m>;
or
string object<>;
The constant m is the upper bound on how many bytes a string can have. Skip it, like in the second one, and it's assumed to be (2**32) - 1, the maximum length π Again, m normally comes from a protocol spec. Like, a filing protocol might say a file name can't be longer than 255 bytes:
string filename<255>;
And the layout πΈ
0 1 2 3 4 5 ...
+-----+-----+-----+-----+-----+-----+...+-----+-----+...+-----+
| length n |byte0|byte1|...| n-1 | 0 |...| 0 |
+-----+-----+-----+-----+-----+-----+...+-----+-----+...+-----+
|<-------4 bytes------->|<------n bytes------>|<---r bytes--->|
|<----n+r (where (n+r) mod 4 = 0)---->|
STRING
Same rule as before: encoding a length bigger than the max in the spec is an error π
3.11. Fixed-length Array π
for fixed-length arrays of the same type, the declaration looks like this:
type-name identifier[n];
The elements are numbered 0 through n-1, and they get encoded one at a time in their natural order, 0 through n-1 π§ Every element's size is a multiple of four bytes. Even though they're all the same type, the elements can have different sizes. For example, in a fixed-length array of strings, every element is type "string", but each one can be a different length π
+---+---+---+---+---+---+---+---+...+---+---+---+---+
| element 0 | element 1 |...| element n-1 |
+---+---+---+---+---+---+---+---+...+---+---+---+---+
|<--------------------n elements------------------->|
FIXED-LENGTH ARRAY
3.12. Variable-length Array π¦
counted arrays let you have variable-length arrays of the same type π The array is encoded as the element count n (an unsigned integer), then the encoding of each element, starting with element 0 and going all the way through element n-1. The declaration follows this form:
type-name identifier<m>;
or
type-name identifier<>;
The constant m is the max element count the array will accept. If you skip m, like in the second one, it's assumed to be (2**32) - 1 β¨
0 1 2 3
+--+--+--+--+--+--+--+--+--+--+--+--+...+--+--+--+--+
| n | element 0 | element 1 |...|element n-1|
+--+--+--+--+--+--+--+--+--+--+--+--+...+--+--+--+--+
|<-4 bytes->|<--------------n elements------------->|
COUNTED ARRAY
If the value of n is bigger than the max in the spec, it's an error π ββοΈ
3.13. Structure ποΈ
structures get declared like this:
struct {
component-declaration-A;
component-declaration-B;
...
} identifier;
The components are encoded in the order they were declared in the structure π Each component's size is a multiple of four bytes, even though the components can be different sizes πΈ
+-------------+-------------+...
| component A | component B |... STRUCTURE
+-------------+-------------+...
3.14. Discriminated Union π₯
a discriminated union is a type made of a discriminant, followed by a type picked from a set of prearranged types based on the discriminant's value π The discriminant's type is either "int", "unsigned int", or an enumerated type, like "bool". The component types are called "arms" of the union, and each one is preceded by the discriminant value that tells you how to encode it. Here's the declaration:
union switch (discriminant-declaration) {
case discriminant-value-A:
arm-declaration-A;
case discriminant-value-B:
arm-declaration-B;
...
default: default-declaration;
} identifier;
Each "case" keyword is followed by a legal value of the discriminant. The default arm is optional. If you don't specify it, then a valid encoding of the union can't take on unspecified discriminant values π The size of the implied arm is always a multiple of four bytes.
The discriminated union gets encoded as its discriminant, followed by the encoding of the implied arm π§
0 1 2 3
+---+---+---+---+---+---+---+---+
| discriminant | implied arm | DISCRIMINATED UNION
+---+---+---+---+---+---+---+---+
|<---4 bytes--->|
3.15. Void π«§
an XDR void is a 0-byte quantity, so basically nothing π Voids are useful for describing operations that take no data as input or no data as output. They're also handy in unions, where some arms have data and others don't. The declaration is just:
void;
And here's how it looks π
++
|| VOID
++
--><-- 0 bytes
3.16. Constant π
the data declaration for a constant looks like this:
const name-identifier = n;
"const" gives a symbolic name to a constant, but it doesn't declare any data β¨ That symbolic constant can go anywhere a regular constant can. For example, this defines a symbolic constant DOZEN, equal to 12:
const DOZEN = 12;
3.17. Typedef π°
"typedef" doesn't declare any data either. It just defines new identifiers for declaring data π The syntax is:
typedef declaration;
The new type name is actually the variable name in the declaration part of the typedef. For example, this defines a new type called "eggbox" using an existing type called "egg":
typedef egg eggbox[DOZEN];
Variables declared with the new type name have the same type that the new type name would have in the typedef, if it were treated as a variable. For example, these two declarations are equivalent for the variable "fresheggs" π₯
eggbox fresheggs;
egg fresheggs[DOZEN];
When a typedef involves a struct, enum, or union definition, there's another (preferred) syntax you can use to define the same type π«Ά In general, a typedef like this:
typedef <<struct, union, or enum definition>> identifier;
can be turned into the alternative form by removing the "typedef" part and putting the identifier after the "struct", "union", or "enum" keyword, instead of at the end. For example, here are the two ways to define the type "bool":
typedef enum { /* using typedef */
FALSE = 0,
TRUE = 1
} bool;
enum bool { /* preferred alternative */
FALSE = 0,
TRUE = 1
};
This syntax is preferred because you don't have to wait until the end of a declaration to figure out the name of the new type π
3.18. Optional-data π·
Optional-data is one kind of union, but it shows up so often that it gets its own special syntax π It's declared like this:
type-name *identifier;
That's equivalent to this union:
union switch (bool opted) {
case TRUE:
type-name element;
case FALSE:
void;
} identifier;
It's also equivalent to this variable-length array declaration, since the boolean "opted" can be read as the length of the array:
type-name identifier<1>;
Optional-data isn't that exciting on its own, but it's super useful for describing recursive data structures, like linked lists and trees π³ For example, this defines a type "stringlist" that encodes lists of strings with arbitrary length:
struct *stringlist {
string item<>;
stringlist next;
};
It could have been equivalently declared as this union:
union stringlist switch (bool opted) {
case TRUE:
struct {
string item<>;
stringlist next;
} element;
case FALSE:
void;
};
or as a variable-length array:
struct stringlist<1> {
string item<>;
stringlist next;
};
Both of those declarations hide what the stringlist type is really for, so the optional-data declaration is preferred over both π The optional-data type also lines up closely with how recursive data structures get represented in high-level languages like Pascal or C, using pointers. In fact, the syntax is the same as the C language's pointer syntax π«Ά
3.19 Areas for Future Enhancement β¨
okay so XDR has no way to represent bit fields or bitmaps, because the whole standard is built on bytes π« . Packed (or binary-coded) decimals are missing too π.
The XDR standard was never trying to describe every kind of data anyone has ever sent or will ever want to send between machines π ββοΈ. It only covers the most commonly used data types of high-level languages like Pascal or C, so apps written in those languages can talk to each other easily over some medium π§.
Picture extending XDR so it could describe almost any existing protocol, like TCP π. The minimum you'd need for that is support for different block sizes and byte-orders. The XDR in this doc could then be called the 4-byte big-endian member of a bigger XDR family ππ.
4. DISCUSSION β¨
(1) Why use a language for describing data? What's wrong with diagrams?
there are so many perks to using a data-description language like XDR instead of diagrams π. Languages are more formal than diagrams, so they lead to less ambiguous descriptions of data π§ . They're also easier to understand, and they let you think about other issues instead of getting lost in low-level bit-encoding details π«Ά. There's also a close analogy between XDR's types and a high-level language like C or Pascal, which makes building XDR encoding and decoding modules way easier π₯. And finally, the language specification is itself an ASCII string that can be passed from machine to machine to do on-the-fly data interpretation π€―.
(2) Why is there only one byte-order for an XDR unit?
supporting two byte-orderings would need a higher level protocol to figure out which byte-order the data is encoded in π€. XDR isn't a protocol, so that can't happen here π. But the upside is that data in XDR format can be written to a magnetic tape, for example, and any machine can interpret it, since no higher level protocol is needed to figure out the byte-order π.
(3) Why is the XDR byte-order big-endian instead of little-endian? Isn't this unfair to little-endian machines such as the VAX(r), which has to convert from one form to the other?
yes, it's unfair π, but having only one byte-order means you have to be unfair to somebody π
. Plenty of architectures, such as the Motorola 68000* and IBM 370*, support big-endian byte-order πΈ.
(4) Why is the XDR unit four bytes wide?
there's a tradeoff when picking the XDR unit size βοΈ. A small size like two keeps the encoded data small, but causes alignment problems for machines that aren't aligned on those boundaries π. A large size like eight means the data will be aligned on virtually every machine, but the encoded data grows too big π΅βπ«. So we went with four as a compromise β¨. Four is big enough to support most architectures efficiently, except for rare machines like the eight-byte aligned Cray* π¦. It's also small enough to keep the encoded data at a reasonable size π.
(5) Why must variable-length data be padded with zeros?
this one is so smart π₯Ή. It's desirable that the same data encodes into the same thing on all machines, so encoded data can be meaningfully compared or checksummed π«Ά. Forcing the padded bytes to be zero is what guarantees that π.
(6) Why is there no explicit data-typing?
data-typing costs a lot for what small advantages it might have πΈ. One cost is the expansion of data from the inserted type fields π¦. Another is the extra cost of interpreting those type fields and acting on them π’. And most protocols already know what type they expect, so data-typing only supplies redundant information π. BUT you can still get the benefits of data-typing with XDR π. One way is to encode two things: first a string which is the XDR data description of the encoded data, and then the encoded data itself π§. Another way is to assign a value to all the types in XDR, then define a universal type that takes this value as its discriminant and, for each value, describes the corresponding data type π.
5. THE XDR LANGUAGE SPECIFICATION π
5.1 Notational Conventions
this spec uses an extended Back-Naur Form notation to describe the XDR language π. Here's a quick rundown of the notation:
- The characters
|,(,),[,],", and*are special. π¨ - Terminal symbols are strings of any characters surrounded by double quotes.
- Non-terminal symbols are strings of non-special characters.
- Alternative items are separated by a vertical bar ("|").
- Optional items are enclosed in brackets.
- Items are grouped together by enclosing them in parentheses.
- A
*following an item means 0 or more occurrences of that item.
For example, consider the following pattern π:
"a " "very" (", " "very")* [" cold " "and "] " rainy "
("day" | "night")
An infinite number of strings match this pattern. A few of them are π:
"a very rainy day"
"a very, very rainy day"
"a very cold and rainy day"
"a very, very, very cold and rainy night"
5.2 Lexical Notes
- Comments begin with
/*and terminate with*/. π¬ - White space serves to separate items and is otherwise ignored. π«§
- An identifier is a letter followed by an optional sequence of letters, digits or underbar (
_). The case of identifiers is not ignored. π€ - A constant is a sequence of one or more decimal digits, optionally preceded by a minus-sign (
-). π’
5.3 Syntax Information
bestie, here's the whole grammar π€π«Ά. Copy it exactly, no edits π:
declaration:
type-specifier identifier
| type-specifier identifier "[" value "]"
| type-specifier identifier "<" [ value ] ">"
| "opaque" identifier "[" value "]"
| "opaque" identifier "<" [ value ] ">"
| "string" identifier "<" [ value ] ">"
| type-specifier "*" identifier
| "void"
value:
constant
| identifier
type-specifier:
[ "unsigned" ] "int"
| [ "unsigned" ] "hyper"
| "float"
| "double"
| "bool"
| enum-type-spec
| struct-type-spec
| union-type-spec
| identifier
enum-type-spec:
"enum" enum-body
enum-body:
"{"
( identifier "=" value )
( "," identifier "=" value )*
"}"
struct-type-spec:
"struct" struct-body
struct-body:
"{"
( declaration ";" )
( declaration ";" )*
"}"
union-type-spec:
"union" union-body
union-body:
"switch" "(" declaration ")" "{"
( "case" value ":" declaration ";" )
( "case" value ":" declaration ";" )*
[ "default" ":" declaration ";" ]
"}"
constant-def:
"const" identifier "=" constant ";"
type-def:
"typedef" declaration ";"
| "enum" identifier enum-body ";"
| "struct" identifier struct-body ";"
| "union" identifier union-body ";"
definition:
type-def
| constant-def
specification:
definition *
5.4 Syntax Notes
- The following are keywords and cannot be used as identifiers: "bool", "case", "const", "default", "double", "enum", "float", "hyper", "opaque", "string", "struct", "switch", "typedef", "union", "unsigned" and "void". π«
- Only unsigned constants may be used as size specifications for arrays. If an identifier is used, it must have been declared previously as an unsigned constant in a "const" definition. π
- Constant and type identifiers within the scope of a specification are in the same name space and must be declared uniquely within this scope. πͺͺ
- Similarly, variable names must be unique within the scope of struct and union declarations. Nested struct and union declarations create new scopes. πͺ
- The discriminant of a union must be of a type that evaluates to an integer. That is, "int", "unsigned int", "bool", an enumerated type or any typedefed type that evaluates to one of these is legal. Also, the case values must be one of the legal values of the discriminant. Finally, a case value may not be specified more than once within the scope of a union declaration. π
6. AN EXAMPLE OF AN XDR DATA DESCRIPTION π
here's a short XDR data description of a thing called a "file", which might be used to transfer files from one machine to another πβ¨.
const MAXUSERNAME = 32; /* max length of a user name */
const MAXFILELEN = 65535; /* max length of a file */
const MAXNAMELEN = 255; /* max length of a file name */
/*
* Types of files:
*/
enum filekind {
TEXT = 0, /* ascii data */
DATA = 1, /* raw data */
EXEC = 2 /* executable */
};
/*
* File information, per kind of file:
*/
union filetype switch (filekind kind) {
case TEXT:
void; /* no extra information */
case DATA:
string creator<MAXNAMELEN>; /* data creator */
case EXEC:
string interpretor<MAXNAMELEN>; /* program interpretor */
};
/*
* A complete file:
*/
struct file {
string filename<MAXNAMELEN>; /* name of file */
filetype type; /* info about file */
string owner<MAXUSERNAME>; /* owner of file */
opaque data<MAXFILELEN>; /* file data */
};
Suppose now there's a user named "john" who wants to store his lisp program "sillyprog" that contains just the data "(quit)" π§βπ». His file would be encoded like this π:
OFFSET HEX BYTES ASCII COMMENTS
------ --------- ----- --------
0 00 00 00 09 .... -- length of filename = 9
4 73 69 6c 6c sill -- filename characters
8 79 70 72 6f ypro -- ... and more characters ...
12 67 00 00 00 g... -- ... and 3 zero-bytes of fill
16 00 00 00 02 .... -- filekind is EXEC = 2
20 00 00 00 04 .... -- length of interpretor = 4
24 6c 69 73 70 lisp -- interpretor characters
28 00 00 00 04 .... -- length of owner = 4
32 6a 6f 68 6e john -- owner characters
36 00 00 00 06 .... -- length of file data = 6
40 28 71 75 69 (qui -- file data bytes ...
44 74 29 00 00 t).. -- ... and 2 zero-bytes of fill
7. REFERENCES π
[1] Brian W. Kernighan & Dennis M. Ritchie, "The C Programming Language", Bell Laboratories, Murray Hill, New Jersey, 1978.
[2] Danny Cohen, "On Holy Wars and a Plea for Peace", IEEE Computer, October 1981.
[3] "IEEE Standard for Binary Floating-Point Arithmetic", ANSI/IEEE Standard 754-1985, Institute of Electrical and Electronics Engineers, August 1985.
[4] "Courier: The Remote Procedure Call Protocol", XEROX Corporation, XSIS 038112, December 1981.
8. TRADEMARKS AND OWNERS β¨
okay bestie, last stop! π here's the list of trademarks mentioned in this doc and who owns each one. always give credit where it's due π
SUN WORKSTATION Sun Microsystems, Inc.
VAX Digital Equipment Corporation
IBM-PC International Business Machines Corporation
Cray Cray Research
NFS Sun Microsystems, Inc.
Ethernet Xerox Corporation.
Motorola 68000 Motorola, Inc.
IBM 370 International Business Machines Corporation
that's the whole doc, bestie! π¦π
π¦ where this page comes from
- ietf: rfc1014 1987-06
- π girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms