//-*-c++-*--------------------------------------------------------------
//  deTest.cpp
//   Tests handling of directory entries.
//
//      Unpublished Confidential Information of Hewlett-Packard
//      Company. Do not disclose.  Copyright (c) Hewlett-Packard
//      Company 1995. All rights reserved
// 
// The contents of this software are proprietary and confidential to
// the Hewlett- Packard Company, and are limited in distribution to
// those with a direct need to know.  Individuals having access to
// this software are responsible for maintaining the confidentiality
// of the content and for keeping the software secure when not in use.
// Transfer to any party is strictly forbidden other than as expressly
// permitted in writing by Hewlett-Packard Company.  Unauthorized
// transfer to or possession by any unauthorized party may be a
// criminal offense.
//
//                  RESTRICTED RIGHTS LEGEND
//
//      Use,  duplication,  or disclosure by the U. S. Government is
//      subject to restrictions as set forth in subparagraph (c) (1)
//      (ii) in the Rights in Technical Data and Computer Software
//      clause in DFARS 252.227-7013 or any other successor clause.
//
//                      HEWLETT-PACKARD COMPANY
//                      3000 Hanover St.
//                      Palo Alto, CA  94304 U.S.A.
//
//      Rights for non-DOD U.S. Government Departments and Agencies
//      are as set forth in FAR 52.227-19 (c) (1,2) or any other
//      successor clause.
//
//----------------------------------------------------------------------
//
// $Source: /projects/HMS/nsr/udfAncil/ssTest/deTest.cpp,v $
// $Revision: 1.23 $    $Author: hmgr $
// $State: Exp $        $Locker:  $
// $Date: 96/05/17 15:48:23 $
//

#include <stdlib.h>
#include <string.h>
#include "nsrLib.h"
#include "nsrRSSdv.h"

void printError( Error & errout ) { 
    printf("ERROR: %s \n", (CHAR_PTR) errout.message() ); 
}

void printIfErr( Error & err ) {
    if (err) 
        printError( err );
} // printIfErr

void makeDE(DirEntry & hiImaDE, LogicalVolume * lvp ) {
    // hidden?
    switch( rand() % 2 ) {
    case 0:  hiImaDE.hidden(False); break;
    case 1:  hiImaDE.hidden(True);  break;
    } // switch

    // deleted?
    switch( rand() % 2 ) {
    case 0:  hiImaDE.deleted(False); break;
    case 1:  hiImaDE.deleted(True);  break;
    } // switch

    // dir entry type
    switch( rand() % 3) {
    case 0:  hiImaDE.entryType(de_Parent); break;
    case 1:  hiImaDE.entryType(de_Subdir); break;
    case 2:  hiImaDE.entryType(de_File);   break;
    } // switch

    // ICB address
    // Make random extent, pull partiton pointer from the DE
    const UINT32 partRefNo = 0;                         // !!! magic #
    Partition * partp = lvp->partitionp(partRefNo); 
    const UINT32 maxLen = 10;                           // !!! magic #
    const UINT32 pLen = rand() % (maxLen - 1) + 1;      // extent length != 0
    const UINT32 strt = rand() % (partp->numBlocks() - pLen);// extent start
    LogExtent randomExtent( partp, strt, pLen );
    hiImaDE.setICBAddress( randomExtent );

    // name
    // Note that Parent entries MUST have a name length of 0, and that
    // all others MUST have non-zero name lengths. This test, however,
    // allows all combinations.
    UINT16 len;
    len = rand() % 1000; // Testing name truncation to 254 chars
    BYTE_PTR theName = new BYTE[len];
    for (UINT32 nameFill = 0; nameFill < len; nameFill++) {
        theName[nameFill] = (CHAR) (rand() % (0x7a-0x20) + 0x20);
    }
    String nameStr( theName, len );
    hiImaDE.name( nameStr );

    delete [] theName;
} // makeDE

///////////////////////////////////////////////////////////////////////////
void randomToISO( DirEntry & hiImaDE,
                  ByteArray & buffer, 
                  UINT32 & offset,
                  UINT32 & tagLoc ) {

    const UINT32 extraLength = 1024; // !!! Magic number.  Arbitrary.
    // !!! As currently coded max ISOlen of a DE is 72 + 256 = 328.
    //     fid overhead = 72, max filename = 256
    UINT16 lenBuf;
    UINT32 lenDE;
    Error err;

    lenDE = hiImaDE.ISOlen();
    lenBuf = (UINT16) lenDE + (UINT16) extraLength;
    buffer.setLen( lenBuf );
    offset = (UINT32) (rand() % extraLength); // pick a valid random offset

    hiImaDE.toISO( buffer, offset, tagLoc, err);
    if (err)  {
        printf( "Error returned from DE.toISO(): ");
        printError( err );
    } // if
} // randomToISO

///////////////////////////////////////////////////////////////////////////
// Usage: deTest  [devfilename]
//   devfilename defaults to 'tbox'
//
// Finds the root ICB,
// uses it to quickly set up the logical volume
// Makes random DirEntries, fromISO's them, toISO's them back
// and check that they haven't changed in the process.
//

INT32
main (INT16 argc, CHAR_PTR argv[])
{
    srand(time((time_t *) NULL));
    const UINT32 maxLoop = 1000;  //fromISO/toISO loop 
    Error err;  // holds returned errs

    // OPEN VOLUME
    CONST_CHAR_PTR devFile;
    if (argc < 2) 
        devFile = "tbox";
    else
        devFile = argv[1];

    DriveDevice ddev(devFile);
    if (ddev.error()) {
        printError( ddev.error() );
        return -1;
    } //if

    SingleSurfaceVolume ssVol( &ddev );
    ssVol.fromDisk(err);
    if (err) {
        printError( err );
        return -3;
    } //if

    //Setup lvp from rootICB addr
    LogExtent icbExtent = ssVol.rootICBAddr( err );
    if (err) {
        printError( err );
        return -3;
    } //if

    LogicalVolume * lvp( icbExtent.logVolumep() );

    //SPECIFIC-CASE TESTING OF DIR ENTRY
    //Test isNull() method.
    printf("BEGIN Specific-case testing of DE.\n");
    //Construct a DirEntry, and check for null.
    DirEntry de;
    if (de.isNull() != True) { //Should be null.
        printf("ERROR:  DE's default constructor didn't make a Null DE.\n");
        return -1;
    } // if

    // Now, try to ISO(() to make sure it returns approp. error
    Error errNull;
    ByteArray ba(1024);                 // 1024 is arbitrary.
    de.toISO( ba, 0, 59, errNull);      // 0, 59 is arbitrary.
    if (errNull != NSR::error_DIR_null_DirEntry) {
        printf("ERROR:  No err returned on DE.toISO() of Null DE.\n");
        return -1;
    } // if

#ifdef FUTURE
    // Now, try the getICBAddress() method, and check LogExtent
    LogExtent le;
    de.getICBAddress(le);
    if (le.isNull() != True) {
        printf("ERROR:  DE.getICBAddress() didn't return Null extent for a Null DE.\n");
        return -1;
    } // if
#endif
    printf("OK.  Passed.  END Specific-case testing of DE.\n\n");


    //LOOPTEST ON DIR ENTRY
    DirEntry hiImaDE;
    DirEntry ImasTwin;
    ByteArray buffer;
    UINT32 tagLoc;
    UINT32 offset;

    for (UINT32 i = 0; i < maxLoop; i++) {
        printf( "Loop %ld \n", i);
        makeDE( hiImaDE, lvp );
        tagLoc = i;
        randomToISO( hiImaDE, buffer, offset, tagLoc );
        ImasTwin.fromISO( buffer, offset, tagLoc, lvp, err );

        printf("First DE ISOlen = %ld\n", hiImaDE.ISOlen());
        printf("Secnd DE ISOlen = %ld\n", ImasTwin.ISOlen());
        if (err)  {
            printf( "Error returned from DE.fromISO: ");
            printError( err );
            return -1;
        } // if
        else if (hiImaDE != ImasTwin) {
            printf( "ERROR: The First and Secnd DEs are different. \n");
            printf( "       What was toISO'd != what was fromISO'd.\n");
            hiImaDE.print(3,"toISO Was");
            printf("\n");
            ImasTwin.print(3,"fromISO Returned");
            printf("\n");
            return -1;
        } // if
        else
            printf("OK\n");
        printf("\n");

#ifdef DEBUG2
// This would be a lengthy output.
        String title1( "ToISO'd DirEntry" );
        hiImaDE.print( title1 ); 
        String title2( "FromISO'd DirEntry" );
        ImasTwin.print( title2 ); 
        printf( "---------------------------------\n");
#endif

    }// for

    printf("Test completed SUCCESSFULLY.\n");
    return 0;
} // main()  

