      ----------------------------------------------------------------

                                LibDC42

       Routines for access and manipulation of Disk Copy 4.2 Disk Images

                        Version 0.9.5  2007.01.27

                  A Part of the Lisa Emulator Project

                  Copyright (C) 2007 Ray A. Arachelian
                           All Rights Reserved

                       http://lisa.sunder.net/lisafsh/
                         mailto: ray@arachelian.com

      (If you email, be sure to use a subject that contains the words
       libdc42 and lisaem so that it won't be marked as spam.)

      ----------------------------------------------------------------

      This code is indended to be used by emulators of Apple computers
      and/or to facilitate access to Disk Copy and DART disk archives.

      ----------------------------------------------------------------
      License information:

      This program is free software; you can redistribute it and/or
      modify it under the terms of the GNU General Public License
      as published by the Free Software Foundation; either version 2
      of the License, or (at your option) any later version, as well
      as the LGPL.


      This program is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      GNU General Public License for more details.

      You should have received a copy of the GNU General Public License
      along with this program;  if not, write to:

                    The Free Software Foundation, Inc.,
                       59 Temple Place - Suite 330,
                       Boston, MA 02111-1307, USA.

              or visit: http://www.gnu.org/licenses/gpl.html

             Contact me if you need other licensing options, etc.


      LICENSING NOTE: Portions of this code rely on the LZHUFF.C code
                      released to usenet under the following conditions:


                             LZHUF.C (c)1989 by:
          Haruyasu Yoshizaki, Haruhiko Okumura, and Kenji Rikitake.
       All rights reserved. Permission granted for non-commercial use.


 If your application does not meet the non-commercial use clause, you must
 remove the #define USE_LZHUFF line from this library, and you may not use
 the LZHUFF routines, or you'll have to build your own equivalents.


 This code is unaffiliated with Apple, and Apple retains all trade marks
 for itself, and all versions of the Disk Copy and DART programs.

 Whenever you see the text Disk Copy or DART, you are encouraged to
 visualize a trademark symbol following it, and chant We all we all
 worship Steve Jobs" (just kidding!)


 *************************************************************************

 Requirements:

 This code wants OS support for the POSIX memory mapping (i.e.
 mmap/msync/munmap) It will work without it, and supports either file
 descriptors or file handles, so it is flexible enough to work on other
 operating systems lacking mmap functions.


 *************************************************************************

 The word image refers to a disk image, not a picture or graphic.  In this
 context, disk image is a single file containing all of the sectors and
 associated metadata for a storage medium - i.e. a floppy disk.



 These routines are file system agnostic, that is, they don't care what
 file system the disk images hold.  They allow you to use the DC42 format
 as a container for disk images.  This would makes them useful for various
 emulators of Apple hardware.

 Note that this library can be used to create hard drive images as well,
 but that they are, of course, incompatible with the real Disk Copy.

 DC42 images are ignorant of the physical layout of their media.  That is
 they only know the number of sectors within the container, not the number
 of sides, tracks, or sectors per track of a specific storage
 device/media.  You may need to translate from head/track/sector to
 absolute sector depending on your (emulator's) needs.

 These routines were created from publically released information about
 Apple's Disk Copy and DART programs from code and Apple IIgs tech notes
 found on the web along with some experimentation using disk images.
 Experimental support for coverting DART disk images to DC42 images is
 included, including LZH compressed DART images.


See

 http://www.nulib.com/library/FTN.e00005.htm
 http://web.pdx.edu/~heiss/technotes/ftyp/ftn.e0.0005.html
 http://ftp.uma.es/Mac/Mirrors/Stairwair/source/mungeimage-120-source.sit.bin
 http://developer.apple.com/technotes/tn/tn1023.html

Above URL's are valid as of the time of this writing and contain Apple //
technical notes, and source code that access DC42/DART images.



WARNINGS:

 Note that modern versions of Apple's Disk Copy program do not support
 tags, which the Lisa computer requires for proper operation.  It is
 unadviseable to convert DART disk images using modern versions of Disk
 Copy (i.e. 6.x) as this strips off all tag data in the process.

 It's unwise to mount DiskCopy 4.2 images on a modern Mac, even if the
 image is Mac formatted without having a backup.  Note that some older Mac
 formats cannot be read by modern Mac's.  i.e if they're MFS instead of
 HFS. (This is circa Mac System 5 and earlier.  MFS formatted disks are
 read-only accessible from under System 7, but not sure if OS X or System
 9 can access them.)

 You can try this with MFS:

 http://developer.apple.com/samplecode/MFSLives/index.html

 but note that MFSLives has nothing to do with libdc42, so I can't offer
 any comments about whether it will work for you.



 Tags are an extra bit of data in addition to the 512 byte sectors (12
 bytes for Apple GCR floppies, or 20 for ProFile hard drives) that store
 extra information about the sector such as which file it belongs to in
 order to help repair programs such as the scavenger.  These are vital for
 use on the Lisa.


 This code can also be used to convert DART disk images to Disk Copy 4.2
 images the right way.  Using newer versions of Disk Copy will not do the
 job as they will strip out the extra tag data.  Mac OS doesn't care about
 the tag data, but Lisa disk images require them.  So you'd damage the
 image if you do use newer Disk Copy programs!

 Previous to the existance of this library, the only way to convert DART
 to DC42 images was to use actual floppies with the real DART and Disk
 Copy 4.2 programs on an old Macintosh with a GCR capable floppy drive.


 These routines are experimental, so always excercise caution and make
 proper backups of your disk images before allowing them to access your
 disk images.


 -------------------------------------------------------------------------

 Usage of these routines:


 Allocate a DC42ImageType structure for each disk image you wish to have
 open.  Pass a pointer to this structure to the function calls that
 require it.


 Some of the routines do not access an opened DC42ImageType structure, and
 may only be used with the image file in the closed state.  No checking is
 done, so if you ignore this warning, you'll find the image may be
 corrupted. For example: dc42_create, dart_to_dc42 and dc42_add_tags


 Note that the create function will not open a disk image, and that the two
 are independant operations.

 You can use the dc42_auto_open function to automatically open DART or DC42
 images, but creating is still a separate operation.



 These routines are not guaranteed to be thread-safe.  Use mutext locks
 around calls to them, or limit access to a specific disk image access to
 a single thread.

 You can open as many disk images as you'd like since each one will have
 their own DC42ImageType struct, and buffers.


 Some of the routines do not require you to open a disk image, and infact
 require the disk images they address to not be opened.  For example the
 dart to dc42 conversion.


 While Disk Copy 4.2 uses checksums and cares about them, but this code
 does not.  This is due to performance concerns on large images such as
 ProFile hard drives

 It will be happy to open an image with invalid checksums, but
 on dc42_close, it will calculate the proper checksums and save them.

 Feel free to call the routines to calculate checksums if you wish.



 Note that while Microsoft Windows does have facilities for memory mapped
 I/O, I do not use them in this code.  If you are familiar with Windows
 have have reliable equivalents of mmap, munmap, msync, please contact me.

 If you choose not to use the memory mapped, or RAM modes, the routines
 will allocate a buffer large enough for a single sector and its tags.  So
 you must handle the data immediately, and should not pass the returned
 pointer around to other routines.

 If you use either the memory mapped or RAM modes, it is fairly safe to do
 that, but not recommended.  In the least you should check the mmappedio
 variable is non-zero.



---------------------------------------------------------------------------
The image Open functions:


int dc42_auto_open(DC42ImageType *F, char *filename, char *options)

                Opens a disk image, or a DART image.  If the image is a
                DART image, it will convert it, creating a new DC42 image,
                and then opens the DC42 image.



int dc42_open(DC42ImageType *F, char *filename,char *options)

                Open disk image F from filename with options selected.  F
                must be allocated ahead of time.



int dc42_open_by_handle(DC42ImageType *F, int fd, FILE *fh, long seekstart,
                        char *options)

                Useful for embedded disk images.  i.e. inside a MacBinII
                wrapper.  Pass either fd or fh



Parameters are:

F         pointer to DC42ImageType - you must allocate this yourself before
          calling the open function.  You'll need to pass the pointer to the
          structure to most of the fn's in this library.


filename  path/filename to the disk image.

fd        file descriptor to a previously opened file (with open)
          (cannot use both fh and fd.  pass -1 for fd if using fh.)

fh        file handle to a previously opened file (with fopen)
          (cannot use both fh and fd.  Pass NULL for fh if using fd.)



options: string containing any of the following (last takes precedence.)

r       read only

w       read/write

p       private writes (not written disk, kept in RAM to fool emulators.)
        Any writes made to the image will be discarded on dc42_close.
        this will not work unless either mode "a" or "b" is used, (or "m"
        on a system supporting mmap.)

m       memory mapped I/O if available, else just plain disk I/O

n       never use mmapped I/O, nor RAM, direct to disk.

a       always in RAM. manage it ourselves, even if we have mmapped I/O
        available, this will use RAM.

b       best choice available:
         - if we have mmapped I/O in the OS, use that.
         - otherwise, load the whole image in RAM.

s       sync on write - only for mmaped modes.  will propagate writes
        immediately back to the image on disk.


seekstart       start position inside the fd/fh of start of the Disk Copy
                Image. If 0, will use the current position as per
                lseek/fseek/ftell.


Returns:

error code is returned. (same as F->retval.)

For textual messages, read F->errormsg which contains suitable text for
returning status to the end user.

error codes are:

  0             success

 86             could not open image
 88             image is not a DiskCopy 4.2 file
 89             size of the physical disk image file does not match what
                the image size claims

 -1             null pointer passed for F
 -2             image has no sectors
 -3             image not in RAM/not allocated or mmaped
 -4             no tag data in this image
 -5             file descriptor is negative (file not open?)
 -6             could not open file for reading
 -7             could not create file

 -9             got EOF too soon in dart image
 -10            wrong file type (not dart)


Notes:


dc42_open_by_handle:

                If the file containing the DC42 image has checksums or
                CRC's it is your responsability to recalculate and update
                those after closing the DC42 image.

                When you issue the open call to get the file descriptor,
                you must ensure that it matches the permissions you ask
                for in the options to dc42_open_by_handle.   i.e. if you
                use 'w', the fd must have been opened in r/w mode, not
                read only!



---------------------------------------------------------------------------
The image close functions:

int dc42_close_image(DC42ImageType *F);

  or

int dc42_close_image_by_handle(DC42ImageType *F)



These functions close the disk image and if it was requested on the call,
will write the data back to the disk, updating the checksums.

Danger! You must call the appropriate function.  If you used
dc42_open_by_handle, you must call dc42_close_image_by_handle, and then
call either close() or fclose() depending on what you used.  At that
point, should the container file that holds the DC42 image have checksums
or such, you should calculate them so as to maintain the integrity of the
file.


---------------------------------------------------------------------------
The create function.


int dc42_create(char *filename, char *volname, uint32 datasize,
                uint32 tagsize)

Creates a blank new disk image.  datasize and tagsize sizes are in bytes.
This will not open the image, only creates it.

filename        The name of the file to create.

volname         The internal volume name of the Image.  This is the
                Macintosh volume name for MFS/HFS images.  For other
                image types, you should pass
                "-not a Macintosh disk-"

datasize        The size of the data section of the DC42 image in bytes.
                Use numblocks*512 for this.

tagsize         The size of the tag section of the DC42 image in bytes.
                Use numblocks*12 for this for floppies, or
                    numblocks*24 for Profile hard disk images.


Returns:        error code or zero.


--------------------------------------------------------------------------
The read functions:

uint8 *dc42_read_sector_tags(DC42ImageType *F, uint32 sectornumber);
uint8 *dc42_read_sector_data(DC42ImageType *F, uint32 sectornumber);

Parameters:

F               an opened DC42ImageType handle.

sectornumber    the sector number whose data to fetch.

Returns:        NULL on error (see F->retval and F->errormsg for details)
                or pointer to the data.

You must use the returned data immediately before performing another
operation on this file.  Do not overwrite it, or free() it.

This is because if you're not using mmapped I/O or RAM, the pointer to the
data will be re-used between calls, and therefore old pointers from
previous reads cannot be considered to be valid!

(It is safe to call both read_sector_tags and read_sector_data for the same
sector and use the pointers returned.)

--------------------------------------------------------------------------
The write functions


int dc42_write_sector_tags(DC42ImageType *F, uint32 sectornumber,
                           uint8 *tagdata); // write tag data to a sector


int dc42_write_sector_data(DC42ImageType *F, uint32 sectornumber,
                           uint8 *data);    // write sector data to a sector


Parameters:

F               an opened DC42ImageType handle.

sectornumber    the sector number whose data/tags to write.

tagdata         pointer to tag data to write to the image for the sector.

data            pointer to data to write to the image for the sector.



Returns:        0 for success
                error code
                (see F->retval and F->errormsg for details)


---------------------------------------------------------------------------
Status functions:


For these functions, you must pass the handle to an opened DC42 image.



uint32 dc42_has_tags(DC42ImageType *F);

       returns 0 if no tags, 1 if it has tags



uint32 dc42_calc_tag_checksum(DC42ImageType *F);

       calculates and returns the current tag checksum.



uint32 dc42_calc_data_checksum(DC42ImageType *F);

       calculates and returns the current data checksum.



uint32 dc42_get_tagchecksum(DC42ImageType *F);

       Returns the tag checksum of the Disk Image.
       Can compare this against dc42_calc_tag_checksum after open
       to verify that the image is good.



uint32 dc42_get_datachecksum(DC42ImageType *F);

       Returns the data checksum of the Disk Image.
       Can compare this against dc42_calc_data_checksum after open
       to verify that the image is good.

       i.e.:

       if ( dc42_get_tagchecksum(F)   ==  dc42_calc_tag_checksum(F)   &&
            dc42_get_datachecksum(F)  ==  dc42_calc_data_checksum(F)    )
            puts("Passed checksum test.");


For these functions, you must not pass a file that is in use or already
opened:



int dc42_is_valid_image(char *filename);

    returns 0 if it can't access the file, or if the image is not a valid
    dc42 image.   returns 1 on success.


int dart_is_valid_image(char *dartfilename);

    returns 0 if it can't access the file, or if the image is not a valid
    DART image.   returns 1 on success.



F               pointer to DC42ImageType - must be allocated and opened
                before calling the function.

filename        path/filename to the DC42 disk image.

dartfilename    path/filename to the DART disk image.

---------------------------------------------------------------------------
Other functions:

int     dc42_recalc_checksums(DC42ImageType *F);

        Calculates and saves the checksums back to the image.
        Called automatically on close. Returns 0 on success, error code
        otherwise.

int     dc42_sync_to_disk(DC42ImageType *F);
        like fsync/fflush, sync's writes changes back to the file when
        using mmap or RAM.  Does not recalculate checksums.
        Returns 0 on success, error code otherwise.


int     dc42_set_volname(DC42ImageType *F,char *name);
        Sets the internal DiskCopy 4.2 volume name to name.  Name must be
        less than 64 chars.  Returns 0 on success, error code otherwise.


char    *dc42_get_volname(DC42ImageType *F);
        Returns the name of the internal Diskcopy 4.2 volume name.


int     dc42_add_tags(char *filename, uint32 tagsize)
        Adds tags to an image that lacks them.
        tagsize is in bytes.  Use 400*2*12 for a 400K floppy.

        The file must NOT be opened when calling this function!
        returns 0 on succes, error code otherwise.



Parameters:

F               pointer to DC42ImageType - must be allocated and opened
                before calling the function.

name            name of internal DC42 volume to set.

tagsize         size of tags in bytes.

filename        path/filename of DC42 image.

---------------------------------------------------------------------------
Conversion:


int dart_to_dc42(char *dartfilename, char *filename);

    Converts a DART file to a DC42 file.  It will not open the DC42 image
    for you, only convert.  Note that this process is quite slow and may
    take several minutes on older machines!


filename        path/filename to the DC42 disk image.

dartfilename    path/filename to the DART disk image.



Returns         0 on success, or error code.

---------------------------------------------------------------------------

