FOR PROGRAMMERS ONLY ==================== You've been warned! The following has NOTHING TO DO with playing Chip's Challenge. It deals with the clipboard format used by CHIPEDIT for cut/paste operations, and assumes some basic knowledge of the C programming language, the internal representation of CC levels in CHIPS.DAT, and of Win32 programming. It does not describe how to read and write to/from the clipboard, but merely explains the format of the objects placed there by the editor. ==================== The editor uses two different clipboard formats to support cut/paste operations between level files. Both formats are largely based on the encoding used to record levels in the CHIPS.DAT file rather than on some internal representation of CHIPEDIT. I had not foreseen that other programmers might be interested in sharing the clipboard data, however, so the clipboard format names do refer to ChipEdit. The two formats are: 1) A block of data which describes 1 or more complete levels, in sequence, within a map file ("CHIPEDIT_LEVELS"). 2) A block of data which describes a rectangular area within a single level ("CHIPEDIT_MAPSECT"). In order to communicate levels with CHIPEDIT via the clipboard it will be necessary for your program to obtain Windows "handles" to these clipboard formats. Somewhere in your program prior to executing Clipboard operations a C program will need to call "RegisterClipboardFormat" with the strings CHIPEDIT_LEVELS and CHIPEDIT_MAPSECT, and save the resulting handles. The system call may be different for VB or other programming languages. Both layouts are based on the format of the levels in CHIPS.DAT, since that is something that any CHIPS tool should understand regardless of how it maintains the Chips data internally. However, there is a structure internal to CHIPEDIT used in the clipboards, used to refer to the arrays of bytes which encode each level. typedef struct { unsigned short encoding_size; char *encoding; } level_t; The editor represents a data file by an array of these objects together with the count of the number of objects. For each level, "encoding_size" is the number of bytes in the CHIPS.DAT representation of the level encoding. "encoding" is a pointer to the stream of bytes which encodes the level. Although "encoding" is a "char *", it should not be interpreted as a null terminated string. It is a byte array of size "encoding size" and there may be 0 bytes included in the middle of the block of memory, and the last byte need not be a 0 byte. With respect to the clipboard (and, within the editor, to any data file) the encoding buffers are not necessarily individually allocated blocks of memory. Here are the formats: Format 1 [ RegisterClipboardFormat("CHIPEDIT_LEVELS") ] - 1 or more complete levels. OFFSET BYTES DESCRIPTION 0 4 Number of levels included in block 4 6 for each level 1 "level_t" structure (see below) for each level. The encoding_size is valid; the encoding pointer is overwritten by the clipboard "read" routine to point to the memory area which follows the level_t structure array. (10) var Encoding of the complete level. This encoding is EXACTLY the form used by CHIPS.DAT for each level. It includes all of the fields (name, password, time limit, both layers of the map, etc. (Internally, The editor keeps all levels encoded in this form; the level you are editting is only decoded while you are viewing it and it is re-encoded when you leave it. The encode/decode operations are not all that expensive (time) and so keeping only the current map "open" reduces the memory management for Win32s apps). A word about the encodings: A level file consists of a header record, followed by a pair of "offset" and "encoding" to get you through the levels. The offset bytes between levels has been replaced by the level_t structure array. However, the editor is otherwise able to use the same encode/decode routines it uses for handling CHIPS.DAT files to convert the file-based level encoding to and from its internal data structures. The levels are written to the clipboard in reverse order of the way they appear in the map, so that a "paste" operation is simply a matter of inserting each level one at a time at the "current spot" (level you are currently editting) (without moving the current spot). When the insertions are complete, the last level inserted becomes the current level and is the one you are looking at. The encoding pointers are arranged sequentially, not reversed. The first level in the level_t array has its level encoded first in the blob of encoded bytes, but it will appear last when the paste operation is complete. After you read the clipboard data, you would point the "encoding" pointer of the first level_t structure to the blob of bytes following the end of the level_t array (you need to know the number of levels given by the first longword) and the size of a level_t structure - preferably coded using "sizeof". The first pointer gets that address; to compute each succeeding address simply add the encoding size. There is likely to be non-zero data in the encoding fields posted to the clipboard. These values refer to the address space of the posting application and are not likely to be valid in the application retrieving the data. When reading the clipboard the application must compute and back-fill the encoding pointers to be relative to the buffer into which the reading application read the data. The operation of posting a group of levels to the clipboard involves encoding the levels as though you were writing them to CHIPS.DAT, and creating an array of structures which includes a length longword and a pointer to the beginning of each encoded blob of data (in the editor this is the way levels are maintained anyway; only the current level is "expanded"). For the clipboard it is necessary that the encoded blobs follow each other consecutively. I am not sure if the editor would handle the case where the encoding length is longer than the actual encoding (with NUL or garbage bytes filling out the intervening space). Therefore, once the editor knows what is being sent to the clipboard, it does a single malloc - 4 bytes for the number of levels + sizeof(level_t) for each level + the sum of the encoded lengths for each level. Format 2 [ RegisterClipboardFormat("CHIPEDIT_MAPSECT") ] OFFSET BYTES DESCRIPTION 0 4 Width of region 4 4 Height of region 8 6 Single "level_t" structure (encoding pointer is ignored) 14 var Encoding of level, in CHIPS.DAT format. The encoded level is made by taking a brand new empty level (32x32 of empty squares) and filling in the selected rectangle into the top left corner of the new grid. The internal level data structure of the new level includes any links where both the button and the linked element fall within the rectangle, and it includes any monsters in the movable monster list which fall within the rectangle (all coordinates are adjusted for the offset move from possibly in the middle of some user's level to being in the top left corner). The result is a mostly empty level where only the top "width" by "height" squares are filled in, but the method of pasting involves reading the width and height and only interpreting the tiles in the top subsection of the map. For a rectangle of size 1 the level is pretty dull, but the region could be 31x31 or even 32x32; the format seemed most likely to be general (that is, any encoding I might have designed on my own would probably have left some key element out that would have annoyed mapmakers the world over.) The encoding format includes a compression mechanism for the map, so that a 1x1 map does not require the whole 32x32 (1024?) bytes to encode, and levels are not so large / the encode decode operations are not so complex (in C) that this extra space/time becomes a burden. It is up to the Paste operation to validate that operation - i.e., decide whether to allow pasting a rectangle which might extend beyond the right or bottom edge of a map, and decide what to do if the addition of monsters, traps, or clone links would overflow the link arrays of the level being pasted into. Prior to pasting, the editor "erases" (places blank tiles) in all of the squares under the paste rectangle. The operation of replacing a tile includes removing monsters or links from the associated lists. For a map section cut/paste block, the title, password, and hint are not examined (it is worth considering whether to copy the hint text if a hint square appears in the region). The encoding includes the unsigned short bytes for level number (which gets reassigned at paste time), time limit, and number of chips, monster, trap, and clone lists. It also includes the title, password, and hint. That is, it is a complete level encoding, not just the compressed map rectangles. The editor does "recalculate" titles whose name begins "LEVEL nn" so that "nn" is adjusted to wherever the level falls in its new position. The editor does not check that the region width or height is less than or equal to 33, and it does not check that monster, trap, or clone links fall within the region of interest. A region posted to the clipboard which violates these rules would therefore mess up the resulting data file something fierce! Example 1: CHIPEDIT_LEVELS. Assume 1) that an array of bytes ARR holds the clipboard buffer. 2) that the encoding for 4 levels is "AAAAA", "BBB", "CCCCCCCCC", and "DDDD". These are not valid CC encodings; but for the purposes of a simple clear example please assume that they are. The data posted to the clipboard would be: OFFSET BYTES DATA 0 4 (long) 4 4 2 (uns short) 4 (encoding size of 4th level) 6 4 (char *) &arr[28]. Points to encoding of 4th level (which occurs first in the clipboard buffer). When written to the clipboard, this field will not be valid. The reading application must recompute this field after reading. 10 2 (uns short) 9 (encoding size of 3rd level) 12 4 (char *) &arr[32]. 16 2 (uns short) 3 (encoding size of 2nd level) 18 4 (char *) &arr[41]. 22 2 (uns short) 5 (encoding size of 1st level) 24 4 (char *) &arr[44]. 28 4 "DDDD" (encoding of 4th level). 32 9 "CCCCCCCCC" (encoding of 3rd level). 41 3 "BBB" (encoding of 2nd level). 44 5 "AAAAA" (encoding of 1st level). Encoding size: 49 bytes. Note that this is the buffer prior to writing to the clipboard. When reading the clipboard, the fields containing addresses to "&arr[]" will have garbage. The pointers must be recalculated based on the other data. Example 2: CHIPEDIT_MAPSECT Assume that a CHIPEDIT level is a 9x9 instead of a 32x32 grid, and that you want to post the 2x5 region (two rows, 5 columns) starting at 4,3 (1 based - fourth row, third column). The map is: ABCDEFGHI JKLMNOPQR STUVWXYZ0 abcdefghi jklmnopqr stuvwxyz1 123456789 ZYXWVUTSR ihgfecdba You would first create a level that looks like this: abcde.... jklmn.... ......... ......... ......... ......... ......... ......... ......... It does not matter what tiles are in the "." positions. The editor will always use "blank" tiles. In addition to the tiles, monster, clone button, and trap links may appear in the linkage lists, with positions relative to the NEW map. These WILL be interpreted by the editor. The help, password, time limit, and other fields will be ignored. The editor will not encode these fields when writing a map section. Encode the new level as though you were writing it to the data file. Assume that the encoding comes out to "FFFFFFFFFF". It doesn't, but pretend it did. The data posted to the clipboard would be: OFFSET BYTES DATA 0 4 (long) 5 (width of region) 4 4 (long) 2 (height of region) 8 2 (uns short) 10 (encoding size of level) 18 4 (char *) &arr[22]. Points to encoding of level (ignored) 22 10 "FFFFFFFFFF" Encoding size: 32 bytes Note that this is the buffer prior to writing to the clipboard. When reading the clipboard, the field containing an address to "&arr[]" will have garbage. The pointer must be recalculated based on the other data. I hope this is complete and understandable to anyone interested. JKE