# Storing data and/or code in the header of a disc file

This document describes how it is possible to store useful data and/or code in the header of a disc file. (This is useful especially for coding competitions where there is a limit to the file size).

The method that is described here is known to work on the standard Amstrad CPC disc operating system (AMSDOS). It may not work if a different disc operating system is installed because it relies on the structure of AMSDOS's work RAM. This method will work even if there are additional ROMs attached.

The method described here relies on these facts:

- The file has a valid header,
- The header will be stored in AMSDOS's work RAM and can be accessed after the file has loaded,
- To load a file, AMSDOS doesn't need all of the variables stored in the file header so the unused variables can be safely used to store data and/or program code.

## File header detection

Whenever a file is opened, AMSDOS will do the following:

- load the first sector (512 bytes) of the file into work RAM.
- generate a checksum from bytes 0-66 inclusive.
- compare the computed checksum against bytes 67 and 68 of the loaded header, (bytes 67 and 68 are used to store the checksum of the header in the file header),

  If the checksums match, then a valid header has been identified.

If a valid header is detected, then the program data will immediatly follow the file header, otherwise the program data begins at the start of the file.

Notes:

- Binary and BASIC files always have a header.
- If a file does not have a header, then it can't be LOADed or RUN from BASIC without a "Direct command" error.

## Header usage

To load a file, AMSDOS doesn't require all the variables in the header.

This table gives a list of the variables required by AMSDOS:

Offset | Length | Description
--- | --- | ---
18 | 1 | Filetype (note 1)
21 | 2 | Load address (note 2)
24 | 2 | Length (note 3)
26 | 2 | Execution Address (note 4)
64 | 3 | Length (note 5)
67 | 2 | Checksum (note 6)

Notes:

1. The "filetype" defines the type of the file: e.g. &00 for a unprotected BASIC file, and &02 for a unprotected binary file
2. The "load address" is the Z80 memory address the file is loaded to. This is normally &170 for BASIC programs, and can be any value for BINARY programs.
3. The "length" is the length of the file in bytes,
4. If the file is binary, and the program is started with the "RUN" command, then the program will be executed starting from this address.
5. This defines the length of the file in bytes and is the same as the length parameter described in note 3. However, this variable allows a file longer than 64K to be defined.
6. The checksum is initialised with 0, and calculated from the sum of the data bytes in the range 0-66 inclusive. The checksum must be valid or AMSDOS will assume that the file does not have a header.

The remaining bytes are not used and can be filled with code and/or program data.

## Method

The first 128 bytes of the file are stored in a 128-byte buffer.

This can be accessed immediatly after loading and will exist until another file is loaded.

The code to get the start of the stored header in AMSDOS's work RAM is:

    ;; get start of AMSDOS work RAM
    ld hl,(&be7d)						; this variable is initialised by AMSDOS
    ;; add on offset of loaded header
    ld bc,&e4
    add hl,bc
    ;; HL = start of record buffer

### Initialising the header

The header written to the start of a file is located at offset &9f from the start of AMSDOS work RAM.

The header can't be filled with user data and/or code before the file is opened for output with "cas out open" because this function modifies the header data in the following way:

- The file type is set to &16 (ASCII)
- The load address is set to the address of the 2K buffer parameter to the "cas out open" function.
- The filename and extension are defined.
- All other bytes are set to "0"

If the in-memory header is filled with user data and/or code after "cas out open" but before "cas out direct", then the following variables are changed:

Offset | Length | Variable
--- | --- | ---
9 | 3 | Extension (note 8)
18 | 1 | Filetype (note 1)
19,20 | 2 | (note 7)
21 | 2 | Load address (note 2)
23 | 2 | (note 7)
24 | 2 | Length (note 3)
26 | 2 | Execution Address (note 4)
64 | 2 | Length (note 5)
67 | 2 | Checksum (note 6)

NOTES:

1. This variable is set to the file type parameter (A register) of the "cas out direct" function
2. This variable is set to the load address parameter (HL register) of the "cas out direct" function
3. This variable is set to the length parameter (DE register) of the "cas out direct" function
4. This variable is set to the execution address (BC register) of the "cas out direct" function
5. If the file is less than 65535 bytes, then this variable is set to the length parameter (DE register) of the "cas in direct" function
6. This variable is computed from the header and contains a valid checksum.
7. These variables are set to "0".
8. This variable is filled with the extension of the filename
9. All other bytes are not changed

Therefore to use all the bytes that are unused during loading the following method must be used:

- Open the file with "cas out open"
- Generate a header in memory, fill it with user data and/or code
- write this to the output file byte-by-byte using "cas out char"
- write the remaining file data using "cas out char"
- close the file with "cas out close"

If "cas out char" is used, then the in-memory header will be defined as ASCII, and the header will not be written to the output file, and the user has full control over the data that will be in the output file.