280 lines
8.4 KiB
C++
280 lines
8.4 KiB
C++
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// jolietdevice.cpp - Access Joliet volumes from SINGLDR
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
//
|
||
|
|
||
|
#include "jolietdevice.h"
|
||
|
#include "fnames.h"
|
||
|
|
||
|
#pragma warning(disable: 4505) // Compiler generated constructor unreferenced
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Private Data
|
||
|
static uint32 MaxBlocksInBuffer;
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Private Function
|
||
|
|
||
|
// helper function to match an ASCII string from the ini file
|
||
|
// against a Unicode entry in a directory
|
||
|
int CompareJolietEntry(LPCHAR filename, uint8 len, uint8 __far * entry)
|
||
|
{
|
||
|
// first check length of file identifier at offset 32
|
||
|
if (2 * len != entry[32]) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// now try to match all chars
|
||
|
for (uint8 indx = 0; indx < len-1; indx++) {
|
||
|
if (UCase(filename[indx]) != UCase(entry[33 + 2 * indx + 1])) {
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Private Method
|
||
|
|
||
|
// given a file name and a directory, populate a FilePtr structure
|
||
|
// or return an empty one if the file doesn't exist in the directory
|
||
|
int JolietDevice::DirLookup(LPCHAR filename,
|
||
|
uint8 len,
|
||
|
FilePtr directory,
|
||
|
FilePtr file) __far
|
||
|
{
|
||
|
uint16 numblocks =
|
||
|
(uint16) ((directory->Size + BlockSize - 1) / BlockSize);
|
||
|
|
||
|
uint8 __far * buffer = FileBuffer; // for progressing through buffer
|
||
|
uint16 bytecounter = 0; // count # bytes of dir entry we've already checked
|
||
|
|
||
|
// read the directory from the disk (32KB limit)
|
||
|
if (directory->Size>0x7FFF) {
|
||
|
printf("Directory too large\n");
|
||
|
return -1;
|
||
|
}
|
||
|
BiosDiskRead(buffer,
|
||
|
directory->FirstBlock,
|
||
|
numblocks,
|
||
|
(uint16)BootDrive);
|
||
|
|
||
|
// scan through entries:
|
||
|
while (bytecounter < directory->Size) {
|
||
|
// check this entry
|
||
|
if (CompareJolietEntry(filename, len, buffer) == 1) {
|
||
|
// on success, save the info for this file and exit
|
||
|
file->FirstBlock = *((uint32 __far *)(buffer+2));
|
||
|
file->Size = *((uint32 __far *)(buffer+10));
|
||
|
return 0;
|
||
|
}
|
||
|
else {
|
||
|
uint8 tmp = buffer[0];
|
||
|
buffer += tmp;
|
||
|
bytecounter += (uint16)buffer[0];
|
||
|
// handle the zero-padding that might exist to
|
||
|
// block-align the next entry:
|
||
|
while (buffer[0] == 0 && bytecounter < directory->Size) {
|
||
|
buffer++;
|
||
|
bytecounter++;
|
||
|
}
|
||
|
}
|
||
|
if (bytecounter == directory->Size) {
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Public Methods
|
||
|
|
||
|
static int IsJolietSignature(uint8 __far* buffer)
|
||
|
{
|
||
|
// check the signatures: chars 1-5 = "CD001" and
|
||
|
// chars 88-90 = 0x25 0x2fh 0x45
|
||
|
return (buffer[0] == 2 &&
|
||
|
buffer[1] == 'C' &&
|
||
|
buffer[2] == 'D' &&
|
||
|
buffer[3] == '0' &&
|
||
|
buffer[4] == '0' &&
|
||
|
buffer[5] == '1' &&
|
||
|
buffer[88] == 0x25 &&
|
||
|
buffer[89] == 0x2f &&
|
||
|
buffer[90] == 0x45);
|
||
|
}
|
||
|
|
||
|
int JolietDevice::OpenDevice() __far
|
||
|
{
|
||
|
uint8 currentblock;
|
||
|
|
||
|
// allocate memory for reading a block
|
||
|
FileBuffer = (uint8 __far *) alloc(0x7FFF, 0); // 32KB
|
||
|
|
||
|
// temp to make using far pointers easier
|
||
|
uint8 __far * buffer = FileBuffer;
|
||
|
|
||
|
// find the SVD
|
||
|
currentblock = 16;
|
||
|
do {
|
||
|
BiosDiskRead(FileBuffer, currentblock, 1, BootDrive);
|
||
|
currentblock++;
|
||
|
if (buffer[0] == 0xFF) {
|
||
|
// somehow we couldn't find the SVD even
|
||
|
// though we booted off of it...
|
||
|
printf("Unable to find Joliet SVD");
|
||
|
return -1;
|
||
|
}
|
||
|
} while (!IsJolietSignature(buffer));
|
||
|
|
||
|
// get the block size
|
||
|
uint16 tmp16 = *((uint16 __far *)(buffer+128));
|
||
|
BlockSize = tmp16;
|
||
|
MaxBlocksInBuffer = 0x7FFF / BlockSize;
|
||
|
|
||
|
// read the root directory info
|
||
|
RootStartBlock = *((uint32 __far *)(buffer+158));
|
||
|
RootSize = *((uint32 __far *)(buffer+166));
|
||
|
|
||
|
// display results
|
||
|
printf("\nCD Configuration\n");
|
||
|
printf("------------------------------\n");
|
||
|
printf("Boot Drive = %2xh\n", BootDrive);
|
||
|
printf("Block Size = %8xh\n", BlockSize);
|
||
|
printf("Root Start = %8xh\n", RootStartBlock);
|
||
|
printf("Root Size = %8xh\n", RootSize);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int JolietDevice::CloseDevice() __far
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int JolietDevice::GetFileProperties(LPCHAR filename,
|
||
|
FilePtr file,
|
||
|
FilePtr directory) __far
|
||
|
{
|
||
|
LPCHAR fname = filename;
|
||
|
uint8 len;
|
||
|
int result;
|
||
|
char c;
|
||
|
|
||
|
// we'll continually recycle the File and Directory structs
|
||
|
directory->FirstBlock = RootStartBlock;
|
||
|
directory->Size = RootSize;
|
||
|
file->Size = 0;
|
||
|
file->FirstBlock = 0;
|
||
|
|
||
|
// traverse through the filename, identifying tokens and
|
||
|
// looking them up in the current context
|
||
|
bool done = 0;
|
||
|
while (!done) {
|
||
|
// consume the leading '/'
|
||
|
while (fname[0] == '/') {
|
||
|
fname++;
|
||
|
}
|
||
|
|
||
|
// failure condition: whitespace
|
||
|
if (IsEndToken(fname[0])) {
|
||
|
printf("CD: Invalid filename: ");
|
||
|
PutFName(filename);
|
||
|
printf("\n");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
// find the next separator in the filename ('/' or whitespace),
|
||
|
// store it, and replace it with 0
|
||
|
len = ShortFNameLength(fname);
|
||
|
c = fname[len];
|
||
|
fname[len] = 0;
|
||
|
|
||
|
// look it up and put the results into File
|
||
|
result = DirLookup(fname, len, directory, file);
|
||
|
|
||
|
// undo the change we made to the filename:
|
||
|
fname[len] = c;
|
||
|
|
||
|
if (result == -1) {
|
||
|
printf("CD: File not found: ");
|
||
|
PutFName(filename);
|
||
|
printf("\n");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
// check loop termination condition
|
||
|
if (c != '/') {
|
||
|
done = 1;
|
||
|
}
|
||
|
else {
|
||
|
fname += len;
|
||
|
// transfer results from File into Directory
|
||
|
directory->FirstBlock = file->FirstBlock;
|
||
|
directory->Size = file->Size;
|
||
|
file->Size = 0;
|
||
|
file->FirstBlock = 0;
|
||
|
}
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
INT16 JolietDevice::ReadFileLow(LPCHAR /* filename */,
|
||
|
FilePtr file,
|
||
|
uint8 __far * buffer) __far
|
||
|
{
|
||
|
uint32 size = file->Size;
|
||
|
uint16 blocks = (uint16) ((size + BlockSize - 1) / BlockSize);
|
||
|
|
||
|
BiosDiskRead(buffer, file->FirstBlock, blocks, BootDrive);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
UINT32 JolietDevice::ReadFileHigh(LPCHAR /* filename */,
|
||
|
FilePtr file,
|
||
|
uint32 destinationAddress,
|
||
|
uint32 /* cbDestinationAddress */) __far
|
||
|
{
|
||
|
uint32 bytesread = 0;
|
||
|
uint32 nextdestination = destinationAddress;
|
||
|
uint32 nextblocknum = file->FirstBlock;
|
||
|
uint32 bufferaddress = PointerToUint32(FileBuffer);
|
||
|
|
||
|
while (bytesread < file->Size) {
|
||
|
uint32 blocksThisRead = ((file->Size - bytesread) + BlockSize - 1) / BlockSize;
|
||
|
if (blocksThisRead > MaxBlocksInBuffer) {
|
||
|
blocksThisRead = MaxBlocksInBuffer;
|
||
|
}
|
||
|
uint32 bytesThisRead = blocksThisRead * BlockSize;
|
||
|
|
||
|
// do the read
|
||
|
BiosDiskRead(FileBuffer, nextblocknum, (uint16) blocksThisRead, BootDrive);
|
||
|
|
||
|
// move the data into extended memory
|
||
|
PModeTransfer(bufferaddress, nextdestination, bytesThisRead);
|
||
|
|
||
|
// get next block number
|
||
|
nextblocknum += blocksThisRead;
|
||
|
|
||
|
// update the count of bytes read
|
||
|
bytesread += bytesThisRead;
|
||
|
|
||
|
// and update the destination address
|
||
|
nextdestination += bytesThisRead;
|
||
|
}
|
||
|
|
||
|
// since we read full blocks at the bios level, we should trim
|
||
|
// our count back down a bit here
|
||
|
if (bytesread > file->Size) {
|
||
|
bytesread = file->Size;
|
||
|
}
|
||
|
return bytesread;
|
||
|
}
|