Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
BuildISO.c
/* |
File: BuildISO.c |
Description:Try to build a ISO 9660 floppy disc, interactively. |
Currently only builds the Primary Volume Descriptor |
and puts files at the root level. Does not do |
subdirectories. |
Author: BB |
Copyright: Copyright: © 1988-1999 by Apple Computer, Inc. |
all rights reserved. |
Disclaimer: You may incorporate this sample code into your applications without |
restriction, though the sample code has been provided "AS IS" and the |
responsibility for its operation is 100% yours. However, what you are |
not permitted to do is to redistribute the source as "DSC Sample Code" |
after having made changes. If you're going to re-distribute the source, |
we require that you make it clear in the source that the code was |
descended from Apple Sample Code, but that you've made changes. |
Change History (most recent first): |
6/24/99 Updated for Metrowerks Codewarror Pro 2.1(KG) |
1/94 Converted to Universal Headers. Fixed a bug which prevented |
Apple extensions from working correctly. |
5/90 Modified for d e v e l o p and Think C 4.0 |
7/1/88 Original Version for the Macintosh(BB) |
*/ |
#include <stdio.h> |
#include <ctype.h> |
#include <string.h> |
#include <Files.h> |
#include <OSUtils.h> |
#include <Memory.h> |
#include <Errors.h> |
#include <strings.h> |
#include <Devices.h> |
#include <MacMemory.h> |
#include "HighSierra.h" |
#include "BuildISO.h" |
#define FLOPPY_SIZE 0x186 /* size in 2k blocks of a 800k floppy */ |
#include "ErrorMsg.h" |
#include "i_o.h" |
#include "Support.h" |
#include "MyDialog.h" |
Str255 nullStr = "\p"; |
Str255 rootName = "\p\000"; |
Str255 parentName = "\p\001"; |
/************************************************************************ |
* |
* Function: CreatePVD |
* |
* Purpose: create the contents of the Primary Volume Descriptor. |
* |
* Returns: void |
* |
* Side Effects: adds to the output file. |
* |
* Description: go through all the primary volume descriptor, showing |
* each field in all it's glory. We don't bother showing |
* the extra blanks at the end of each string field. |
* |
* |
************************************************************************/ |
OSErr |
CreatePVD(short referenceNumber) |
{ |
PVD p; |
OSErr result; |
long offset; |
char volID[33]; |
Boolean goOn; |
ClearOut((char *)&p, sizeof(p)); |
p.VDType = 1; |
p.VSStdId[0] = 'C'; |
p.VSStdId[1] = 'D'; |
p.VSStdId[2] = '0'; |
p.VSStdId[3] = '0'; |
p.VSStdId[4] = '1'; |
p.VSStdVersion = 1; |
CharCopy(p.systemIdentifier, "Apple Computer, Inc., Type:0001", sizeof(p.systemIdentifier)); |
goOn = AskForString((char *)"\pWhat do you want to call this volume? (32 characters or less)", volID); |
if (goOn == false) |
return -1; |
NormalizeVolumeName(volID); |
CharCopy(p.volumeIdentifier, volID, sizeof(p.volumeIdentifier)); |
p.lsbVolumeSpaceSize = NormalizeLong((long)FLOPPY_SIZE); |
p.msbVolumeSpaceSize = (long)FLOPPY_SIZE; |
p.lsbVolumeSetSize = NormalizeWord(FLOPPY_SIZE); |
p.msbVolumeSetSize = FLOPPY_SIZE; |
p.lsbVolumeSetSequenceNumber = NormalizeWord(1); |
p.msbVolumeSetSequenceNumber = 1; |
p.lsbLogicalBlockSize = NormalizeWord(CDBLKSIZE); |
p.msbLogicalBlockSize = CDBLKSIZE; |
p.lsbPathTableSize = NormalizeLong(PATHTBLSIZE); |
p.msbPathTableSize = PATHTBLSIZE; |
p.lsbPathTable1 = NormalizeLong(LSBPATH); |
p.msbPathTable1 = MSBPATH; |
p.lsbPathTable2 = 0L; |
p.msbPathTable2 = 0L; |
/* Exercise for reader: get the time via GetTime() and convert |
** to string of the format shown below for these strange dates. |
** Use that date and time to fill the various volume date fields. |
** The date shown is my daughter's birth date and time... |
*/ |
CharCopy(p.volumeCreation, "19870914060100000", sizeof(p.volumeCreation)); |
CharCopy(p.volumeModification, "19870914060100000", sizeof(p.volumeModification)); |
CharCopy(p.volumeExpiration, "00000000000000000", sizeof(p.volumeExpiration)); |
CharCopy(p.volumeEffective, "19870914060100000", sizeof(p.volumeEffective)); |
p.FileStructureStandardVersion = 1; |
SpaceOut(p.volumeSetIdentifier, sizeof(p.volumeSetIdentifier)); |
SpaceOut(p.publisherIdentifier, sizeof(p.publisherIdentifier)); |
SpaceOut(p.dataPreparerIdentifier, sizeof(p.dataPreparerIdentifier)); |
SpaceOut(p.applicationIdentifier, sizeof(p.applicationIdentifier)); |
SpaceOut(p.copyrightFileIdentifier, sizeof(p.copyrightFileIdentifier)); |
SpaceOut(p.abstractFileIdentifier, sizeof(p.abstractFileIdentifier)); |
SpaceOut(p.bibliographicFileIdentifier, sizeof(p.bibliographicFileIdentifier)); |
CreateDirRcd((DirRcd *)&p.rootDirectoryRecord, rootName, |
DIRECTORY, CDBLKSIZE, (short) directoryBit, 0L, 0L, 0); |
p.Reserved1 = 0; |
ClearOut(p.Reserved2, sizeof(p.Reserved2)); |
ClearOut(p.Reserved3, sizeof(p.Reserved3)); |
p.Reserved4 = 0; |
#ifdef VERBOSE /* if I want to verify what I've done */ |
DumpPVD(&p); |
#endif |
offset = (long) HSVOLSTART * (long) CDBLKSIZE; |
result = isoWrite(referenceNumber, (Ptr)&p, (long) sizeof(p), (long)offset); |
if (result != noErr) |
ErrorMsg("CreatePVD: isoWrite() returned %d", result); |
else |
ErrorMsg("volume descriptors successfully created."); |
return result; |
} |
/************************************************************************ |
* |
* Function: CreateVDT |
* |
* Purpose: create the contents of the Volume Descriptor Terminator |
* |
* Returns: void |
* |
* Side Effects: adds to the output file. |
* |
* Description: Build a simple VDT, fill it in, and write it out to |
* a famous place. |
* |
* |
************************************************************************/ |
OSErr |
CreateVDT(short referenceNumber) |
{ |
PVD p; |
OSErr result; |
long offset; |
ClearOut((char *)&p, sizeof(p)); |
p.VDType = 255; |
p.VSStdId[0] = 'C'; |
p.VSStdId[1] = 'D'; |
p.VSStdId[2] = '0'; |
p.VSStdId[3] = '0'; |
p.VSStdId[4] = '1'; |
p.VSStdVersion = 1; |
offset = (long) HSTERMSTART * (long) CDBLKSIZE; |
result = isoWrite(referenceNumber, (Ptr)&p, (long) sizeof(p), (long)offset); |
if (result != noErr) |
ErrorMsg("CreateVDT: isoWrite() returned %d", result); |
return result; |
} |
/************************************************************************ |
* |
* Function: CreatePathTable |
* |
* Purpose: create path tables |
* |
* Returns: nothing |
* |
* Side Effects: writes lsb path table and msb path table |
* |
* Description: We'll assume just the root. Dump out the path |
* path table in both formats. We'll put the |
* path table in famous spots. |
* |
************************************************************************/ |
OSErr |
CreatePathTable(short referenceNumber) |
{ |
char buffer[CDBLKSIZE]; |
PathTableRecordPtr d; |
long offset; |
OSErr result; |
ClearOut(buffer, sizeof(buffer)); |
d = (PathTableRecordPtr) &buffer[0]; |
d->len_di = 1; |
d->XARlength = 0; |
d->dirLocation = NormalizeLong(DIRECTORY); |
d->parentDN = 0; |
offset = LSBPATH * (long) CDBLKSIZE; |
result = isoWrite(referenceNumber, buffer, (long) CDBLKSIZE, offset); |
if (result != noErr) |
ErrorMsg("CreatePathTable: isoWrite() returned %d", result); |
d->len_di = 1; |
d->dirLocation = DIRECTORY; |
d->parentDN = 0; |
offset = MSBPATH * (long) CDBLKSIZE; |
result = isoWrite(referenceNumber, buffer, (long) CDBLKSIZE, offset); |
if (result != noErr) |
ErrorMsg("CreatePathTable: isoWrite() returned %d", result); |
return result; |
} |
/************************************************************************ |
* |
* Function: CreateDirRcd |
* |
* Purpose: Create a directory record for a file |
* |
* Returns: none |
* |
* Side Effects: fills *d with directory information. We assume |
* caller has allocated space for d. |
* |
* Description: |
* |
************************************************************************/ |
void |
CreateDirRcd(DirRcd *d, StringPtr name, long start, long length, short flags, OSType fType, OSType fCreator, short finderFlags) |
{ |
Ptr dPtr; |
DateTimeRec today; |
d->XARlength = 0; |
d->lsbStart = NormalizeLong(start); |
d->msbStart = start; |
d->lsbDataLength = NormalizeLong(length); |
d->msbDataLength = length; |
d->fileFlags = flags; |
if (finderFlags & fInvisible) |
d->fileFlags |= existenceBit; |
GetTime(&today); |
d->year = today.year-1900; |
d->month = today.month; |
d->day = today.day; |
d->hour = today.hour; |
d->minute = today.minute; |
d->second = today.second; |
d->gmtOffset = 0; |
d->interleaveSize = 0; |
d->interleaveSkip = 0; |
d->lsbVolSetSeqNum = NormalizeWord(1); |
d->msbVolSetSeqNum = 1; |
d->len_fi = CreateISOName((char *)d->fi, name); |
d->len_dr = 32 + d->len_fi; |
AddAppleExtensions(d, fType, fCreator, finderFlags); |
if (d->len_dr & 1) /* odd dirRcds need pad byte */ |
{ |
dPtr = (char *)d; |
dPtr[d->len_dr] = '\000'; |
d->len_dr++; |
} |
} |
/************************************************************************ |
* |
* Function: AddOldAppleExtensions |
* |
* Purpose: optionally add apple extensions to ISO 9660 |
* |
* Returns: void |
* |
* Side Effects: directory record may get extended. Must have enough |
* room in area pointed to by dirRcd for this to happen. |
* |
* Description: Check the fType. If it's non-zero, add the information |
* necessary for the Apple Extensions to ISO 9660. Note |
* that we can't just assign fType and fCreator, since |
* longs are aligned within structures. |
* |
* This procedure adds the old, "BA" Apple extensions. |
* |
************************************************************************/ |
void |
AddOldAppleExtensions(DirRcd *dirRcd, OSType fType, OSType fCreator, short flags) |
{ |
OldAppleExtension apple; |
short i; |
short j; |
short limit; |
char *aPtr; |
Ptr fPtr; |
if (fType != 0L) |
{ |
apple.macFlag[0] = 'B'; |
apple.macFlag[1] = 'A'; |
apple.systemUseID = 06; |
fPtr = (char *)&fType; |
for (i = 0; i < 4; i++) |
apple.fileType[i] = fPtr[i]; |
fPtr = (char *)&fCreator; |
for (i = 0; i < 4; i++) |
apple.fileCreator[i] = fPtr[i]; |
apple.finderFlags[0] = (flags >> 8) & 0xFF; |
apple.finderFlags[1] = flags & 0xFF; |
limit = sizeof(apple); |
aPtr = (char *)&apple; |
j = dirRcd->len_fi; |
if (!(j & 1)) /* 9401 bug fix BL¡B */ |
{ |
dirRcd->fi[j] = 0; |
j++; /* there is a pad byte after odd length file names */ |
} |
for (i = 0; i <= limit; i++) |
dirRcd->fi[i + j] = aPtr[i]; |
dirRcd->len_dr += limit; |
} |
} |
/************************************************************************ |
* |
* Function: AddAppleExtensions |
* |
* Purpose: optionally add apple extensions to ISO 9660 |
* |
* Returns: void |
* |
* Side Effects: directory record may get extended. Must have enough |
* room in area pointed to by dirRcd for this to happen. |
* |
* Description: Check the fType. If it's non-zero, add the information |
* necessary for the Apple Extensions to ISO 9660. Note |
* that we can't just assign fType and fCreator, since |
* longs are aligned within structures. |
* |
************************************************************************/ |
void |
AddAppleExtensions(DirRcd *dirRcd, OSType fType, OSType fCreator, short flags) |
{ |
AppleExtension apple; |
short i; |
short j; |
short limit; |
char *aPtr; |
Ptr fPtr; |
if (fType != 0L) |
{ |
apple.signature[0] = 'A'; |
apple.signature[1] = 'A'; |
apple.extensionLength = 0x0E; |
apple.systemUseID = 02; |
fPtr = (char *)&fType; |
for (i = 0; i < 4; i++) |
apple.fileType[i] = fPtr[i]; |
fPtr = (char *)&fCreator; |
for (i = 0; i < 4; i++) |
apple.fileCreator[i] = fPtr[i]; |
apple.finderFlags[0] = (flags >> 8) & 0xFF; |
apple.finderFlags[1] = flags & 0xFF; |
limit = sizeof(apple); |
aPtr = (char *)&apple; |
j = dirRcd->len_fi; |
if (!(j & 1)) /* 9401 bug fix BL¡B */ |
{ |
dirRcd->fi[j] = 0; |
j++; /* there is a pad byte after odd length file names */ |
} |
for (i = 0; i <= limit; i++) |
dirRcd->fi[i + j] = aPtr[i]; |
dirRcd->len_dr += limit; |
} |
} |
/************************************************************************ |
* |
* Function: CopyDirRcdToBuffer |
* |
* Purpose: copy directory record to buffer |
* |
* Returns: nothing |
* |
* Side Effects: buffer is filled a little bit more |
* |
* Description: copy a directory record to the buffer. |
* |
************************************************************************/ |
void |
CopyDirRcdToBuffer(DirRcd *d, char *b) |
{ |
char *dPrime; |
short i; |
dPrime = (char *)d; |
for (i = 0; i < d->len_dr; i++) |
*b++ = *dPrime++; |
} |
/************************************************************************ |
* |
* Function: CopyRsrcFork |
* |
* Purpose: copy the resource fork of a file |
* |
* Returns: OSErr |
* mostly noErr, but could be |
* ioErr and the like if isoWrite complains. |
* |
* Side Effects: floppy gets new data written on it. |
* |
* Description: we have a starting location, "start", and a length. |
* Allocate an appropriate buffer and read from the file |
* specified by "name" and "vRefNum". Write that information |
* out to the floppy using our isoWrite call. |
* |
************************************************************************/ |
OSErr |
CopyRsrcFork(short referenceNumber, StringPtr name, short vRefNum, long start, long length) /* how much to write */ |
{ |
Ptr rsrcBuf; |
ParamBlockRec pb; |
Boolean goOn; |
OSErr result; |
long physicalLength; |
short myRefNum; |
ClearOut((Ptr)&pb, sizeof(pb)); |
goOn = true; |
physicalLength = ROUND_UP(length); |
rsrcBuf = NewPtrClear(physicalLength); |
if (rsrcBuf == NULL) |
{ |
ErrorMsg("Can't allocate %ld bytes for CopyRsrcFork()", length); |
return mFulErr; /* nothing to clean up */ |
} |
pb.ioParam.ioCompletion = NULL; |
pb.ioParam.ioNamePtr = name; |
pb.ioParam.ioVRefNum = vRefNum; |
pb.ioParam.ioVersNum = 0; |
pb.ioParam.ioPermssn = fsCurPerm; |
pb.ioParam.ioMisc = NULL; |
result = PBOpenRF(&pb, false); |
if (result != noErr) |
{ |
ErrorMsg("CopyRsrcFork: PBOpenRF returned %d", result); |
ErrorMsg("vRefNum %d, name %P", vRefNum, name); |
C2PStr((char *)name); |
goOn = false; |
} |
if (goOn) |
{ |
myRefNum = pb.ioParam.ioRefNum; |
result = FSRead(myRefNum, &length, rsrcBuf); |
if (result != noErr) |
{ |
ErrorMsg("CopyRsrcFork: FSRead returned %d", result); |
goOn = false; |
} |
} |
if (goOn) |
{ |
result = isoWrite(referenceNumber, rsrcBuf, physicalLength, start); |
if (result != noErr) |
{ |
ErrorMsg("CopyRsrcFork: isoWrite returned %d", result); |
goOn = false; |
} |
} |
PBClose(&pb, false); |
DisposePtr(rsrcBuf); |
return result; |
} |
/************************************************************************ |
* |
* Function: CopyDataFork |
* |
* Purpose: copy the resource fork of a file |
* |
* Returns: OSErr |
* mostly noErr, but could be |
* ioErr and the like if isoWrite complains. |
* |
* Side Effects: floppy gets new data written on it. |
* |
* Description: we have a starting location, "start", and a length. |
* Allocate an appropriate buffer and read from the file |
* specified by "name" and "vRefNum". Write that information |
* out to the floppy using our isoWrite call. |
* |
************************************************************************/ |
OSErr |
CopyDataFork(short referenceNumber, StringPtr name, short vRefNum, long start, long length) /* how much to write */ |
{ |
Ptr dataBuf; |
ParamBlockRec pb; |
Boolean goOn; |
OSErr result; |
long physicalLength; |
short myRefNum; |
ClearOut((Ptr)&pb, sizeof(pb)); |
goOn = true; |
physicalLength = ROUND_UP(length); |
dataBuf = NewPtrClear(physicalLength); |
if (dataBuf == NULL) |
{ |
ErrorMsg("Can't allocate %ld bytes for CopyDataFork()", length); |
return mFulErr; /* nothing to clean up */ |
} |
pb.ioParam.ioCompletion = NULL; |
pb.ioParam.ioNamePtr = name; |
pb.ioParam.ioVRefNum = vRefNum; |
pb.ioParam.ioVersNum = 0; |
pb.ioParam.ioPermssn = fsCurPerm; |
pb.ioParam.ioMisc = NULL; |
result = PBOpen(&pb, false); |
if (result != noErr) |
{ |
ErrorMsg("CopyDataFork: PBOpen returned %d", result); |
ErrorMsg("vRefNum %d, name %P", vRefNum, name); |
C2PStr((char *)name); |
goOn = false; |
} |
if (goOn) |
{ |
myRefNum = pb.ioParam.ioRefNum; |
result = FSRead(myRefNum, &length, dataBuf); |
if (result != noErr) |
{ |
ErrorMsg("CopyDataFork: FSRead returned %d", result); |
goOn = false; |
} |
} |
if (goOn) |
{ |
result = isoWrite(referenceNumber, dataBuf, physicalLength, start); |
if (result != noErr) |
{ |
ErrorMsg("CopyDataFork: isoWrite returned %d", result); |
goOn = false; |
} |
} |
PBClose(&pb, false); |
DisposePtr(dataBuf); |
return result; |
} |
/************************************************************************ |
* |
* Function: CreateFiles |
* |
* Purpose: create files in the root of a ISO floppy. |
* |
* Returns: nothing |
* |
* Side Effects: floppy gets new data in famous root area |
* |
* Description: For each file, find the size of the two forks. |
* Copy the resource fork first, then the data fork |
* (associated files come before data files in ISO) |
* |
************************************************************************/ |
void |
CreateFiles(short referenceNumber) |
{ |
StringPtr name; |
short vRefNum; |
DirRcd dirRcd; |
long start; /* where we start putting data on the CD */ |
long rsrcLength; |
long dataLength; |
char *b; |
OSErr result; |
OSType fType; |
OSType fCreator; |
short flags; |
short ISOFlags; |
char buffer[CDBLKSIZE]; |
ClearOut(buffer, sizeof(buffer)); |
b = &buffer[0]; |
name = (StringPtr)NewPtr(255); |
if (name == NULL) |
{ |
ErrorMsg("Can't allocate 255 bytes for a string."); |
return; |
} |
CreateDirRcd(&dirRcd, rootName, DIRECTORY, CDBLKSIZE, (short) directoryBit, 0L, 0L, 0); |
CopyDirRcdToBuffer(&dirRcd, b); |
b += dirRcd.len_dr; |
CreateDirRcd(&dirRcd, parentName, DIRECTORY, CDBLKSIZE, (short) directoryBit, 0L, 0L, 0); |
CopyDirRcdToBuffer(&dirRcd, b); |
b += dirRcd.len_dr; |
start = DATASTART * CDBLKSIZE; |
/* Keep asking for names, even if errors occur. Most errors will be because |
* The user tried to copy too big of a file to the floppy. |
*/ |
while (HFSFile(name, &vRefNum) == true) |
{ |
result = GetFileInfo(name, vRefNum, &rsrcLength, &dataLength, &fType, &fCreator, &flags); |
if (result != noErr) |
ErrorMsg("Can't get file information for %s", name); |
else |
{ |
ISOFlags = (flags & fInvisible) ? existenceBit : 0; |
if (rsrcLength != 0L) |
{ |
CreateDirRcd(&dirRcd, name, start/CDBLKSIZE, rsrcLength, ISOFlags | associatedBit, |
fType, fCreator, flags); |
result = CopyRsrcFork(referenceNumber, name, vRefNum, start, rsrcLength); |
if (result == noErr) |
{ |
CopyDirRcdToBuffer(&dirRcd, b); |
b += dirRcd.len_dr; |
start = ROUND_UP(start+rsrcLength); |
} |
else |
ErrorMsg("Failed to copy resource fork."); |
} |
if (result == noErr) |
{ |
CreateDirRcd(&dirRcd, name, start/CDBLKSIZE, dataLength, ISOFlags, |
fType, fCreator, flags); |
result = CopyDataFork(referenceNumber, name, vRefNum, start, dataLength); |
if (result == noErr) |
{ |
CopyDirRcdToBuffer(&dirRcd, b); |
b += dirRcd.len_dr; |
start = ROUND_UP(start+dataLength); |
} |
else |
ErrorMsg("Failed to copy data fork."); |
ClearOut((Ptr)name, 255); |
} |
} |
} |
result = isoWrite(referenceNumber, (Ptr)buffer, (long)sizeof(buffer), (long) (DIRECTORY*CDBLKSIZE)); |
if (result != noErr) |
ErrorMsg("CreateDataFiles: isoWrite of directory records returned %d", result); |
DisposePtr((Ptr)name); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14