File indexing completed on 2024-04-21 04:49:42

0001 /*
0002     SPDX-FileCopyrightText: 1998-2009 Sebastian Trueg <trueg@k3b.org>
0003     SPDX-License-Identifier: GPL-2.0-or-later
0004 */
0005 
0006 #ifndef K3BDEVICE_H
0007 #define K3BDEVICE_H
0008 
0009 #include "k3bdevicetypes.h"
0010 #include "k3bdiskinfo.h"
0011 #include "k3bcdtext.h"
0012 #include "k3bmsf.h"
0013 #include "k3bdevice_export.h"
0014 
0015 #include <qglobal.h>
0016 #include <QVarLengthArray>
0017 
0018 #if defined(__FreeBSD_kernel__)
0019 #undef Q_OS_LINUX
0020 #define Q_OS_FREEBSD 1
0021 #endif
0022 
0023 #ifdef Q_OS_FREEBSD
0024 struct cam_device;
0025 #endif
0026 
0027 #ifdef Q_OS_WIN32
0028 #include <windows.h>
0029 #endif
0030 
0031 namespace Solid {
0032     class Device;
0033     class StorageAccess;
0034 }
0035 
0036 namespace K3b {
0037     namespace Device
0038     {
0039         class Toc;
0040 
0041         typedef QVarLengthArray< unsigned char > UByteArray;
0042 
0043         /**
0044          * \brief The main class representing a device.
0045          *
0046          * Devices are constructed by the DeviceManager.
0047          *
0048          * All methods except for open and close in Device are thread-safe which basically means that
0049          * no two commands are sent to the device at the same time.
0050          */
0051         // FIXME: all methods are const which makes no sense at all!
0052         class LIBK3BDEVICE_EXPORT Device
0053         {
0054         public:
0055 #if defined(Q_OS_FREEBSD)
0056             typedef struct cam_device* Handle;
0057 #elif defined(Q_OS_WIN32)
0058             // file handle
0059             typedef HANDLE Handle;
0060 #else
0061             // file descriptor
0062             typedef int Handle;
0063 #endif
0064 
0065             ~Device();
0066 
0067             Solid::Device solidDevice() const;
0068 
0069             /**
0070              *  Gives interface for dics volume.
0071              *  Keep in mind that it can return empty pointer when no disc is inserted.
0072              *
0073              *  @return Interface for disc volume.
0074              */
0075             Solid::StorageAccess* solidStorage() const;
0076 
0077             /**
0078              * \deprecated use readCapabilities() and writeCapabilities()
0079              * The device type.
0080              *
0081              * @return A bitwise or of K3b::Device::DeviceType.
0082              */
0083             DeviceTypes type() const;
0084 
0085             /**
0086              * The mediatypes this device is able to read.
0087              *
0088              * \return A bitwise or of K3b::Device::MediaType
0089              */
0090             MediaTypes readCapabilities() const;
0091 
0092             /**
0093              * The media types this device is able to write.
0094              *
0095              * \return A bitwise or of K3b::Device::MediaType
0096              */
0097             MediaTypes writeCapabilities() const;
0098 
0099             /**
0100              * \return Vendor string as reported by the device's firmware.
0101              */
0102             QString vendor() const;
0103 
0104             /**
0105              * \return Description string as reported by the device's firmware.
0106              */
0107             QString description() const;
0108 
0109             /**
0110              * \return Version string as reported by the device's firmware.
0111              */
0112             QString version() const;
0113 
0114             /**
0115              * Shortcut for \code writesCd() || writesDvd() \endcode
0116              *
0117              * \return true if the device is able to burn media.
0118              */
0119             bool burner() const;
0120 
0121             /**
0122              * Shortcut for \code type() & DEVICE_CD_R \endcode
0123              *
0124              * \return true if the device is able to burn CD-R media.
0125              */
0126             bool writesCd() const;
0127 
0128             /**
0129              * Shortcut for \code type() & DEVICE_CD_RW \endcode
0130              *
0131              * \return true if the device is able to burn CD-RW media.
0132              */
0133             bool writesCdrw() const;
0134 
0135             /**
0136              * Shortcut for \code writesDvdMinus() || writesDvdPlus() \endcode
0137              *
0138              * \return true if the device is able to burn DVD media.
0139              */
0140             bool writesDvd() const;
0141 
0142 
0143             /**
0144              * Shortcut for \code type() & (DEVICE_DVD_PLUS_R|DEVICE_DVD_PLUS_RW) \endcode
0145              *
0146              * \return true if the device is able to burn DVD+R or DVD+RW media.
0147              */
0148             bool writesDvdPlus() const;
0149 
0150             /**
0151              * Shortcut for \code type() & (DEVICE_DVD_R|DEVICE_DVD_RW) \endcode
0152              *
0153              * \return true if the device is able to burn DVD-R or DVD-RW media.
0154              */
0155             bool writesDvdMinus() const;
0156 
0157             /**
0158              * Shortcut for \code type() & DEVICE_DVD_ROM \endcode
0159              *
0160              * \return true if the device is able to read DVD media.
0161              */
0162             bool readsDvd() const;
0163 
0164             /**
0165              * @deprecated Use burnfree()
0166              */
0167             bool burnproof() const;
0168 
0169             /**
0170              * @return true is the device is a writer and supports buffer underrun free recording (BURNFREE)
0171              */
0172             bool burnfree() const;
0173 
0174             /**
0175              * Shortcut for \code writingModes() & WRITINGMODE_SAO \endcode
0176              *
0177              * \deprecated use supportsWritingMode()
0178              */
0179             bool dao() const;
0180 
0181             /**
0182              * Check if the device supports a certain writing mode.
0183              *
0184              * \return true if the device supports the requested writing mode or false otherwise.
0185              */
0186             bool supportsWritingMode( WritingMode mode ) const { return (writingModes() & mode); }
0187 
0188             /**
0189              * Shortcut for
0190              * \code
0191              *  writingModes() & (WRITINGMODE_RAW|WRITINGMODE_RAW_R16|WRITINGMODE_RAW_R96P|WRITINGMODE_RAW_R96R)
0192              * \endcode
0193              */
0194             bool supportsRawWriting() const;
0195 
0196             /**
0197              * @return true if the device is a DVD-R(W) writer which supports test writing.
0198              */
0199             bool dvdMinusTestwrite() const;
0200 
0201             int maxReadSpeed() const;
0202             int currentWriteSpeed() const;
0203 
0204             /**
0205              * Size of the device's internal writing buffer.
0206              *
0207              * \return The size of the buffer in KB.
0208              */
0209             int bufferSize() const;
0210 
0211             /**
0212              * for SCSI devices this should be something like /dev/scd0 or /dev/sr0
0213              * for IDE device this should be something like /dev/hdb1
0214              */
0215             QString blockDeviceName() const;
0216 
0217             int maxWriteSpeed() const;
0218 
0219             /**
0220              * internal K3b value.
0221              * \deprecated This should not be handled here.
0222              */
0223             void setCurrentWriteSpeed( int s );
0224 
0225             /**
0226              * Use this if the speed was not detected correctly.
0227              */
0228             void setMaxReadSpeed( int s );
0229 
0230             /**
0231              * Use this if the speed was not detected correctly.
0232              */
0233             void setMaxWriteSpeed( int s );
0234 
0235             /**
0236              * checks if unit is ready (medium inserted and ready for command)
0237              *
0238              * Refers to the MMC command: TEST UNIT READY
0239              */
0240             bool testUnitReady() const;
0241 
0242             /**
0243              * checks if disk is empty, returns @p K3b::Device::State
0244              */
0245             int isEmpty() const;
0246 
0247             /**
0248              * @return true if inserted media is rewritable.
0249              */
0250             bool rewritable() const;
0251 
0252             /**
0253              * Check if the inserted media is a DVD.
0254              *
0255              * \return true if the inserted media is a DVD.
0256              */
0257             bool isDVD() const;
0258 
0259             /**
0260              * @return The number of sessions on the media.
0261              */
0262             int numSessions() const;
0263 
0264             /**
0265              * @return The toc of the media or an empty (invalid) K3b::Device::Toc if
0266              *         no or an empty media is inserted.
0267              */
0268             Toc readToc() const;
0269 
0270             /**
0271              * Append ISRC and MCN to the TOC if found
0272              * This has been moved to a separate method since it can take a very long time
0273              * to scan for all ISRCs.
0274              */
0275             void readIsrcMcn( Toc& toc ) const;
0276 
0277             /**
0278              * Read the raw CD-Text data without decoding it.
0279              * \return An array of bytes as read from the device, suitable to be used in
0280              * CdText( const QByteArray& )
0281              *
0282              * \sa readCdText
0283              */
0284             QByteArray readRawCdText( bool* success = 0 ) const;
0285 
0286             /**
0287              * Read the CD-TEXT of an audio or mixed-mode CD.
0288              *
0289              * \return A CdText object filled with the CD-TEXT values or an empty one in case of
0290              *         pure data media or if the CD does not contain CD-TEXT.
0291              *
0292              * \sa readRawCdText
0293              */
0294             CdText readCdText() const;
0295 
0296             /**
0297              * @return The K3b::Device::Track::DataMode of the track.
0298              * @see K3b::Device::Track
0299              */
0300             Track::DataMode getTrackDataMode( const Track& track ) const;
0301 
0302             /**
0303              * @return the mode of a data track. K3b::Device::Track::MODE1, K3b::Device::Track::MODE2,
0304              *         K3b::Device::Track::XA_FORM1, or K3b::Device::Track::XA_FORM2.
0305              */
0306             Track::DataMode getDataMode( const K3b::Msf& sector ) const;
0307 
0308             /**
0309              * block or unblock the drive's tray
0310              * \return true on success and false on error.
0311              * \see eject()
0312              */
0313             bool block( bool ) const;
0314 
0315             /**
0316              * Eject the media.
0317              * \return true on success and false on error.
0318              * \see load()
0319              */
0320             bool eject() const;
0321 
0322             /**
0323              * Load the media.
0324              * @return true on success and false on error.
0325              */
0326             bool load() const;
0327 
0328             /**
0329              * Enable or disable auto-ejecting. For now this is a no-op on non-Linux systems.
0330              * \param enabled if true auto-ejecting will be enabled, otherwise disabled.
0331              * \return true if the operation was successful, false otherwise
0332              */
0333             bool setAutoEjectEnabled( bool enabled ) const;
0334 
0335             /**
0336              * The supported writing modes.
0337              *
0338              * \return A bitwise or of K3b::Device::WritingMode or 0 in case of a read-only device.
0339              */
0340             WritingModes writingModes() const;
0341 
0342             bool readSectorsRaw(unsigned char *buf, int start, int count) const;
0343 
0344             /**
0345              * Get a list of supported profiles. See enumeration MediaType.
0346              */
0347             int supportedProfiles() const;
0348 
0349             /**
0350              * Tries to get the current profile from the drive.
0351              * @returns -1 on error (command failed or unknown profile)
0352              *          MediaType otherwise (MEDIA_NONE means: no current profile)
0353              */
0354             int currentProfile() const;
0355 
0356             /**
0357              * Check if a certain feature is current.
0358              * \see k3bdevicetypes.h for feature constants.
0359              * \return 1 if the feature is current, 0 if not, -1 on error
0360              */
0361             int featureCurrent( unsigned int feature ) const;
0362 
0363             /**
0364              * This is the method to use!
0365              */
0366             DiskInfo diskInfo() const;
0367 
0368             /**
0369              * Refers to MMC command READ CAPACITY
0370              */
0371             bool readCapacity( K3b::Msf& ) const;
0372 
0373             /**
0374              * Refers to MMC command READ FORMAT CAPACITY
0375              *
0376              * @param wantedFormat The requested format type.
0377              * @param result If true is returned this contains the requested value.
0378              * @param currentMax If not 0 this will be filled with the Current/Maximum Descriptor value.
0379              * @param currentMax If not 0 this will be filled with the Current/Maximum Format Type.
0380              */
0381             bool readFormatCapacity( int wantedFormat, K3b::Msf& result,
0382                                      K3b::Msf* currentMax = 0, int* currentMaxFormat = 0 ) const;
0383 
0384             /**
0385              * Determine the type of the currently mounted medium
0386              *
0387              * @returns K3b::Device::MediaType
0388              */
0389             MediaType mediaType() const;
0390 
0391             /**
0392              * Returns the list of supported writing speeds as reported by
0393              * mode page 2Ah.
0394              *
0395              * This only works with MMC3 compliant drives.
0396              */
0397             QList<int> determineSupportedWriteSpeeds() const;
0398 
0399             /**
0400              * @returns the speed in kb/s or 0 on failure.
0401              */
0402             int determineMaximalWriteSpeed() const;
0403 
0404             /**
0405              * Open the device for access via a file descriptor.
0406              * @return true on success or if the device is already open.
0407              * @see close()
0408              *
0409              * Be aware that this method is not thread-safe.
0410              */
0411             bool open( bool write = false ) const;
0412 
0413             /**
0414              * Close the files descriptor.
0415              * @see open()
0416              *
0417              * Be aware that this method is not thread-safe.
0418              */
0419             void close() const;
0420 
0421             /**
0422              * @return true if the device was successfully opened via @p open()
0423              */
0424             bool isOpen() const;
0425 
0426             /**
0427              * fd on linux, cam on bsd
0428              */
0429             Handle handle() const;
0430 
0431             /**
0432              * \return \li -1 on error (no DVD)
0433              *         \li 1 (CSS/CPPM)
0434              *         \li 2 (CPRM) if scrambled
0435              *         \li 0 otherwise
0436              */
0437             int copyrightProtectionSystemType() const;
0438 
0439             // MMC commands
0440 
0441             /**
0442              * SET SPEED command
0443              *
0444              * @param readingSpeed The preferred reading speed (0x0000-0xFFFE). 0xFFFF requests
0445              *                     fot the logical unit to select the optimal speed.
0446              * @param writingSpeed The preferred writing speed (0x0000-0xFFFE). 0xFFFF requests
0447              *                     fot the logical unit to select the optimal speed.
0448              * @param cav Is the speed pure CAV?
0449              */
0450             bool setSpeed( unsigned int readingSpeed,
0451                            unsigned int writingSpeed,
0452                            bool cav = false ) const;
0453 
0454             /**
0455              * if true is returned \param data is resized.
0456              */
0457             bool readDiscInformation( UByteArray& data ) const;
0458 
0459             /**
0460              * @param pf If false all fields in the descriptor data is vendor specific. Default should be true.
0461              */
0462             bool modeSelect( UByteArray& pageData, bool pf, bool sp ) const;
0463 
0464             /**
0465              * if true is returned \param pageData is resized.
0466              */
0467             bool modeSense( UByteArray& pageData, int page ) const;
0468 
0469             /**
0470              * if true is returned \param data is resized.
0471              */
0472             bool readTocPmaAtip( UByteArray& data, int format, bool msf, int track ) const;
0473 
0474             /**
0475              * @param type specifies what value means:
0476              *        \li 00b - value refers to a logical block address
0477              *        \li 01b - value refers to a track number where 0 will treat the lead-in as if it
0478              *                  were a logical track and ffh will read the invisible or incomplete track.
0479              *        \li 10b - value refers to a session number
0480              *
0481              */
0482             bool readTrackInformation( UByteArray& data, int type, int value ) const;
0483 
0484             /**
0485              * if true is returned \param data is resized.
0486              */
0487             bool readDiscStructure( UByteArray& data,
0488                                     unsigned int mediaType = 0x0,
0489                                     unsigned int format = 0x0,
0490                                     unsigned int layer = 0x0,
0491                                     unsigned long address = 0,
0492                                     unsigned int agid = 0x0 ) const;
0493 
0494             /**
0495              * In MMC5 readDvdStructure was renamed to readDiscStructure. This method does the same
0496              * like the above.
0497              */
0498             bool readDvdStructure( UByteArray& data,
0499                                    unsigned int format = 0x0,
0500                                    unsigned int layer = 0x0,
0501                                    unsigned long address = 0,
0502                                    unsigned int agid = 0x0 ) const;
0503 
0504             /**
0505              * if true is returned \param data is resized.
0506              */
0507             bool mechanismStatus( UByteArray& data ) const;
0508 
0509             /**
0510              * Read a single feature.
0511              * data will be filled with the feature header and the descriptor
0512              */
0513             bool getFeature( UByteArray& data, unsigned int feature ) const;
0514 
0515 
0516             /**
0517              * if true is returned \param data is resized.
0518              */
0519             bool getPerformance( UByteArray& data,
0520                                  unsigned int type,
0521                                  unsigned int dataType,
0522                                  unsigned int lba = 0 ) const;
0523 
0524             /**
0525              * @param sectorType: \li 000b - all types
0526              *                    \li 001b - CD-DA
0527              *                    \li 010b - Mode 1
0528              *                    \li 011b - Mode 2 formless
0529              *                    \li 100b - Mode 2 form 1
0530              *                    \li 101b - Mode 2 form 2
0531              *
0532              * @param startAdress Lba 0 is mapped to msf 00:00:00 so this method uses
0533              *                    startAdress+150 as the starting msf.
0534              *
0535              * @param endAdress This is the ending address which is NOT included in the read operation.
0536              *                  Lba 0 is mapped to msf 00:00:00 so this method uses
0537              *                  endAdress+150 as the ending msf.
0538              *
0539              * @param c2:         \li 00b  - No error info
0540              *                    \li 01b  - 294 bytes, one bit for every byte of the 2352 bytes
0541              *                    \li 10b  - 296 bytes, xor of all c2 bits, zero pad bit, 294 c2 bits
0542              *
0543              * @param subChannel: \li 000b - No Sub-channel data
0544              *                    \li 001b - RAW P-W Sub-channel (96 bytes)
0545              *                    \li 010b - Formatted Q Sub-channel (16 bytes)
0546              *                    \li 100b - Corrected and de-interleaved R-W Sub-channel (96 bytes)
0547              */
0548             bool readCdMsf( unsigned char* data,
0549                             unsigned int dataLen,
0550                             int sectorType,
0551                             bool dap,
0552                             const K3b::Msf& startAdress,
0553                             const K3b::Msf& endAdress,
0554                             bool sync,
0555                             bool header,
0556                             bool subHeader,
0557                             bool userData,
0558                             bool edcEcc,
0559                             int c2,
0560                             int subChannel ) const;
0561 
0562             /**
0563              * @param sectorType: \li 000b - all types
0564              *                    \li 001b - CD-DA
0565              *                    \li 010b - Mode 1
0566              *                    \li 011b - Mode 2 formless
0567              *                    \li 100b - Mode 2 form 1
0568              *                    \li 101b - Mode 2 form 2
0569              *
0570              * @param c2:         \li 00b  - No error info
0571              *                    \li 01b  - 294 bytes, one bit for every byte of the 2352 bytes
0572              *                    \li 10b  - 296 bytes, xor of all c2 bits, zero pad bit, 294 c2 bits
0573              *
0574              * @param subChannel: \li 000b - No Sub-channel data
0575              *                    \li 001b - RAW P-W Sub-channel (96 bytes)
0576              *                    \li 010b - Formatted Q Sub-channel (16 bytes)
0577              *                    \li 100b - Corrected and de-interleaved R-W Sub-channel (96 bytes)
0578              */
0579             bool readCd( unsigned char* data,
0580                          unsigned int dataLen,
0581                          int sectorType,
0582                          bool dap,
0583                          unsigned long startAdress,
0584                          unsigned long length,
0585                          bool sync,
0586                          bool header,
0587                          bool subHeader,
0588                          bool userData,
0589                          bool edcEcc,
0590                          int c2,
0591                          int subChannel ) const;
0592 
0593             bool read10( unsigned char* data,
0594                          unsigned int dataLen,
0595                          unsigned long startAdress,
0596                          unsigned int length,
0597                          bool fua = false ) const;
0598 
0599             bool read12( unsigned char* data,
0600                          unsigned int dataLen,
0601                          unsigned long startAdress,
0602                          unsigned long length,
0603                          bool streaming = false,
0604                          bool fua = false ) const;
0605 
0606             /**
0607              * @param subchannelParam: 01h - CD current position
0608              *                         02h - Media Catalog number (UPC/bar code)
0609              *                         03h - ISRC
0610              * @param trackNumber only valid if subchannelParam == 03h
0611              */
0612             bool readSubChannel( UByteArray& data,
0613                                  unsigned int subchannelParam,
0614                                  unsigned int trackNumber ) const;
0615 
0616             bool readIsrc( unsigned int track, QByteArray& isrc ) const;
0617 
0618             bool readMcn( QByteArray& mcn ) const;
0619 
0620             /**
0621              * MMC command Read Buffer Capacity
0622              *
0623              * \return \see ScsiCommand::transport()
0624              */
0625             int readBufferCapacity( long long& bufferLength, long long& bufferAvail ) const;
0626 
0627             /**
0628              * @returns the index number on success
0629              *          -1 on general error
0630              *          and -2 if there is no index info in that frame
0631              */
0632             int getIndex( unsigned long lba ) const;
0633 
0634             bool searchIndex0( unsigned long startSec, unsigned long endSec, long& pregapStart ) const;
0635 
0636             /**
0637              * For now this just searches index 0 for all tracks and sets
0638              * the value in the tracks.
0639              * In the future this should scan for all indices.
0640              */
0641             bool indexScan( Toc& toc ) const;
0642 
0643             /**
0644              * Seek to the specified sector.
0645              */
0646             bool seek( unsigned long lba ) const;
0647 
0648             bool getNextWritableAdress( unsigned int& lastSessionStart, unsigned int& nextWritableAdress ) const;
0649 
0650             /**
0651              * Retrieve the next writable address from the currently mounted writable medium.
0652              * \return The next writable address if the medium is empty or appendable or -1
0653              * if an error occurred.
0654              */
0655             int nextWritableAddress() const;
0656 
0657             /**
0658              * Locks the device for usage. This means that no MMC command can be performed
0659              * until usageUnlock is called.
0660              *
0661              * Locking a device is useful when an external application or library is called
0662              * that opens the device itself.
0663              *
0664              * \sa usageUnlock
0665              */
0666             void usageLock() const;
0667 
0668             /**
0669              * Unlock the device after a call to usageLock.
0670              */
0671             void usageUnlock() const;
0672 
0673             /**
0674              * Thread-safe ioctl call for this device for Linux and Net-BSD systems.
0675              * Be aware that so far this does not include opening the device
0676              */
0677 //      int ioctl( int request, ... ) const;
0678 
0679         protected:
0680             bool furtherInit();
0681 
0682 #ifdef Q_OS_LINUX
0683             /**
0684              * Fallback method that uses the evil cdrom.h stuff
0685              */
0686             bool readTocLinux( Toc& ) const;
0687 #endif
0688 
0689             /**
0690              * The preferred toc reading method for all CDs. Also reads session info.
0691              * undefined for DVDs.
0692              */
0693             bool readRawToc( Toc& ) const;
0694             bool readFormattedToc( Toc&, int mediaType ) const;
0695 
0696             /**
0697              * Fixes the last block on CD-Extra disks. This is needed if the readRawToc failed since
0698              * in that case the first sector of the last session's first track is used as the previous
0699              * session's last track's last sector which is wrong. There is a 11400 block session lead-in
0700              * between them. This method fixes this only for the last session and only on linux.
0701              */
0702             bool fixupToc( Toc& ) const;
0703 
0704         private:
0705             /**
0706              * A Device can only be constructed by the DeviceManager.
0707              */
0708             Device( const Solid::Device& dev );
0709 
0710             /**
0711              * Determines the device's capabilities. This needs to be called once before
0712              * using the device.
0713              *
0714              * Should only be used by the DeviceManager.
0715              *
0716              * @param checkWritingModes if true the CD writing modes will be checked using
0717              *                          MMC_MODE_SELECT.
0718              */
0719             bool init( bool checkWritingModes = true );
0720 
0721             void searchIndexTransitions( long start, long end, K3b::Device::Track& track ) const;
0722             void checkWritingModes();
0723             void checkFeatures();
0724             void checkForJustLink();
0725             void checkFor2AFeatures();
0726             void checkForAncientWriters();
0727 
0728             /**
0729              * Internal method which checks if the raw toc data has bcd values or hex.
0730              * @return 0 if hex, 1 if bcd, -1 if none
0731              */
0732             int rawTocDataWithBcdValues( const UByteArray& data ) const;
0733 
0734             bool getSupportedWriteSpeedsVia2A( QList<int>& list, MediaType type ) const;
0735             bool getSupportedWriteSpeedsViaGP( QList<int>& list, MediaType type ) const;
0736 
0737             int getMaxWriteSpeedVia2A() const;
0738 
0739             QByteArray mediaId( int mediaType ) const;
0740 
0741             class Private;
0742             Private* d;
0743 
0744             friend class DeviceManager;
0745         };
0746 
0747         /**
0748          * This should always be used to open a device since it
0749          * uses the resmgr
0750          *
0751          * @internal
0752          */
0753         K3b::Device::Device::Handle openDevice( const char* name, bool write = false );
0754     }
0755 }
0756 
0757 #endif