| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /** |
| * $Id: OS400PlatformUtils.cpp 568078 2007-08-21 11:43:25Z amassari $ |
| */ |
| |
| // --------------------------------------------------------------------------- |
| // Includes |
| // --------------------------------------------------------------------------- |
| #define MY_XP_CPLUSPLUS |
| #include <xercesc/util/XMLUniDefs.hpp> |
| #include <xercesc/util/XercesDefs.hpp> |
| #include <pthread.h> |
| #include <xercesc/util/PlatformUtils.hpp> |
| #include <xercesc/util/RuntimeException.hpp> |
| #include <xercesc/util/Janitor.hpp> |
| #include <xercesc/util/XMLString.hpp> |
| #include <xercesc/util/XMLHolder.hpp> |
| #include <xercesc/util/PanicHandler.hpp> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <errno.h> |
| #include <unistd.h> |
| #include <qp0z1170.h> |
| #include <mimchint.h> |
| #include <string.h> |
| #include <qmhsndpm.h> |
| #include <qmhrtvm.h> |
| #include <qusec.h> |
| #include <unistd.h> |
| #include <string.h> |
| #include <except.h> |
| #include <mih/cmpswp.h> |
| #include "OS400PlatformUtils.hpp" |
| #include <xercesc/util/OutOfMemoryException.hpp> |
| #include <qlgusr.h> // @1aa |
| #include <qusrjobi.h> // @1aa |
| #include <qusec.h> // @1aa |
| #include "utypes.h" // @1aa |
| #include "iconv_util.hpp" // @1aa |
| #include "iconv_cnv.hpp" // @1aa |
| #include <qmhrtvm.h> // @1aa |
| |
| #if defined (XML_USE_ICONV400_TRANSCODER) |
| #include <xercesc/util/Transcoders/Iconv400/Iconv400TransService.hpp> |
| XERCES_CPP_NAMESPACE_BEGIN |
| void cleanupDefaultConverter(); |
| XERCES_CPP_NAMESPACE_END |
| #elif defined (XML_USE_ICU_TRANSCODER) |
| #include <xercesc/util/Transcoders/ICU/ICUTransService.hpp> |
| #else |
| Transcoder not Specified - For OS/400 must be either ICU or Iconv400 |
| #endif |
| |
| #if defined(XML_USE_MSGFILE_MESSAGELOADER) |
| #include <xercesc/util/MsgLoaders/MsgFile/MsgLoader.hpp> |
| #elif defined(XML_USE_INMEM_MESSAGELOADER) |
| #include <xercesc/util/MsgLoaders/InMemory/InMemMsgLoader.hpp> |
| #else |
| #include <xercesc/util/MsgLoaders/ICU/ICUMsgLoader.hpp> |
| #endif |
| |
| #if defined (XML_USE_NETACCESSOR_SOCKET) |
| #include <xercesc/util/NetAccessors/Socket/SocketNetAccessor.hpp> |
| #endif |
| |
| XERCES_CPP_NAMESPACE_BEGIN |
| |
| char* PackingRepText(const char * const repText1, |
| const char * const repText2, |
| const char * const repText3, |
| const char * const repText4); |
| // --------------------------------------------------------------------------- |
| // XMLPlatformUtils: Platform init method |
| // --------------------------------------------------------------------------- |
| XMLNetAccessor* XMLPlatformUtils::makeNetAccessor() |
| { |
| #if defined (XML_USE_NETACCESSOR_SOCKET) |
| return new (fgMemoryManager) SocketNetAccessor(); |
| #else |
| return 0; |
| #endif |
| } |
| |
| |
| |
| // |
| // This method is called very early in the bootstrapping process. This guy |
| // must create a transcoding service and return it. It cannot use any string |
| // methods, any transcoding services, throw any exceptions, etc... It just |
| // makes a transcoding service and returns it, or returns zero on failure. |
| // |
| |
| XMLTransService* XMLPlatformUtils::makeTransService() |
| #if defined (XML_USE_ICU_TRANSCODER) |
| { |
| return new (fgMemoryManager) ICUTransService; |
| } |
| #elif defined (XML_USE_ICONV400_TRANSCODER) |
| { |
| return new (fgMemoryManager) Iconv400TransService; |
| } |
| #else |
| { |
| return new (fgMemoryManager) IconvTransService; |
| } |
| #endif |
| |
| // |
| // This method is called by the platform independent part of this class |
| // when client code asks to have one of the supported message sets loaded. |
| // In our case, we use the ICU based message loader mechanism. |
| // |
| XMLMsgLoader* XMLPlatformUtils::loadAMsgSet(const XMLCh* const msgDomain) |
| { |
| XMLMsgLoader* retVal; |
| try |
| { |
| #if defined(XML_USE_MSGFILE_MESSAGELOADER) |
| retVal = new (fgMemoryManager) MsgCatalogLoader(msgDomain); |
| #elif defined (XML_USE_ICU_MESSAGELOADER) |
| retVal = new (fgMemoryManager) ICUMsgLoader(msgDomain); |
| #elif defined (XML_USE_ICONV_MESSAGELOADER) |
| retVal = new (fgMemoryManager) MsgCatalogLoader(msgDomain); |
| #else |
| retVal = new (fgMemoryManager) InMemMsgLoader(msgDomain); |
| #endif |
| } |
| catch(const OutOfMemoryException&) |
| { |
| throw; |
| } |
| catch(...) |
| { |
| panic( PanicHandler::Panic_CantLoadMsgDomain ); |
| } |
| return retVal; |
| } |
| |
| // --------------------------------------------------------------------------- |
| // XMLPlatformUtils: The panic method |
| // --------------------------------------------------------------------------- |
| void XMLPlatformUtils::panic(const PanicHandler::PanicReasons reason) |
| { |
| |
| if (fgUserPanicHandler) |
| { |
| fgUserPanicHandler->panic(reason); |
| } |
| |
| // |
| // We just print a message and exit, Note we are currently dependent on |
| // the number of reasons being under 10 for this teo work |
| // |
| else |
| { |
| struct reason_code |
| { |
| char reason_char; |
| char endofstring; |
| }reason_code; |
| |
| reason_code.reason_char = '0'; |
| reason_code.endofstring = '\0'; |
| reason_code.reason_char = reason_code.reason_char + reason; |
| send_message((char*)&reason_code,GENERAL_PANIC_MESSAGE,'e'); |
| } |
| |
| } |
| // --------------------------------------------------------------------------- |
| // XMLPlatformUtils: File Methods |
| // --------------------------------------------------------------------------- |
| unsigned int XMLPlatformUtils::curFilePos(FileHandle theFile |
| , MemoryManager* const manager) |
| { |
| // Get the current position |
| int curPos = ftell( (FILE*)theFile); |
| if (curPos == -1) |
| ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotGetSize, manager); |
| |
| return (unsigned int)curPos; |
| } |
| |
| void XMLPlatformUtils::closeFile(FileHandle theFile |
| , MemoryManager* const manager) |
| { |
| if (fclose((FILE*)theFile)) |
| ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotCloseFile, manager); |
| } |
| |
| |
| unsigned int XMLPlatformUtils::fileSize(FileHandle theFile |
| , MemoryManager* const manager) |
| { |
| // Get the current position |
| long int curPos = ftell((FILE*)theFile); |
| if (curPos == -1) |
| ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotGetCurPos, manager); |
| |
| // Seek to the end and save that value for return |
| if (fseek( (FILE*)theFile, 0, SEEK_END) ) |
| ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotSeekToEnd, manager); |
| |
| long int retVal = ftell( (FILE*)theFile); |
| if (retVal == -1) |
| ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotSeekToEnd, manager); |
| |
| // And put the pointer back |
| if (fseek( (FILE*)theFile, curPos, SEEK_SET) ) |
| ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotSeekToPos, manager); |
| |
| return (unsigned int)retVal; |
| } |
| |
| static char JOBCCSID_CONVERTER_NAME[60] = ""; // @1aa |
| static UConverter *jobCCSID_Converter = NULL; // @1aa |
| void get_jobCCSID_converter() // @1aa |
| { |
| Qwc_JOBI0400_t job_attr; /* Job attribute receive. @1aa */ |
| Qus_EC_t recv_error; /* Error on receive? @1aa */ |
| UErrorCode uerr = U_ZERO_ERROR; /* Error structure for creating converter @1aa */ |
| |
| recv_error.Bytes_Provided = sizeof(recv_error); // @1aa |
| |
| QUSRJOBI(&job_attr, |
| sizeof(job_attr), |
| "JOBI0400", |
| "* ", |
| " ", |
| &recv_error); // extract job ccsid (integer form) @1aa |
| |
| if ( recv_error.Bytes_Available != 0 ) // @1aa |
| { /* The 'QUSRJOBI' API failed for some reason. */ |
| strcpy(JOBCCSID_CONVERTER_NAME, "ibm037"); // use internal default @1aa |
| } |
| else // @1aa |
| { /* Get the default job CCSID. */ |
| int JobCCSID = job_attr.Default_Coded_Char_Set_Id; // @1aa |
| char jobCCSID_str[30]; // @1aa |
| |
| sprintf(jobCCSID_str, "%05d", JobCCSID); // @1aa |
| // convert job CCSID (integer format) to IANA text format. |
| int rc = QlgCvtTextDescToDesc(0, |
| 11, |
| (char *)jobCCSID_str, |
| strlen(jobCCSID_str), |
| &JOBCCSID_CONVERTER_NAME[0], |
| sizeof(JOBCCSID_CONVERTER_NAME), |
| JobCCSID); // @1aa |
| if (rc < 0) // @1aa |
| strcpy(JOBCCSID_CONVERTER_NAME, "ibm037"); // @1aa |
| |
| } |
| |
| // create converter for job CCSID |
| jobCCSID_Converter = createConverter (JOBCCSID_CONVERTER_NAME, &uerr); // @1aa |
| |
| if (U_FAILURE (uerr)) // @1aa |
| { |
| jobCCSID_Converter = NULL; // don't use jobCCSID_Converter @1aa |
| } |
| |
| return; // @1aa |
| } |
| |
| #include <qmhrtvm.h> |
| #include <qusec.h> |
| #include <errno.h> // for UErrorCode @1aa |
| |
| FileHandle XMLPlatformUtils::openFile(const XMLCh* const FILENAME |
| , MemoryManager* const manager) |
| { char errno_id[7]; // @1aa |
| int numChars = (u_strlen(FILENAME)*2) + 2; // @1aa @1bc add 2 bytes for null terminator |
| char* saved_myTarget = new char[numChars]; // target for transcoding to job CCSID @1aa |
| char* myTarget = (char *) saved_myTarget; // ucnv_fromUnicode can change myTarget pointer @1aa |
| memset(myTarget,'\0',numChars); // make sure storage is zeroed out to allow for |
| // automatic null terminator @1ba |
| char* myTargetLimit = myTarget + (numChars - 1); // @1aa |
| const UChar *mySource = (UChar *) FILENAME; |
| |
| int mySourceChars = u_strlen(mySource); // @1aa |
| const UChar* mySourceLimit = (UChar *) mySource + u_strlen(mySource); // @1aa |
| |
| UErrorCode err = U_ZERO_ERROR; /* Error structure for creating converter @1aa */ |
| |
| if (jobCCSID_Converter == NULL) // should only need to create this converter once. @1aa |
| { |
| get_jobCCSID_converter(); // @1aa |
| } |
| |
| // need to do open with pathname/filename in job CCSID, not IBM037. The other |
| // openFile( ) is dead code, so didn't bother with converting the pathname/fileName there. |
| // Alternative to using converter code is to use XLATEMB MI instruction. @1aa |
| const char* TMPFILENAME; |
| if (jobCCSID_Converter != NULL) { |
| ucnv_fromUnicode (jobCCSID_Converter, |
| &myTarget, |
| myTargetLimit, |
| &mySource, |
| mySourceLimit, |
| NULL, |
| TRUE, |
| &err); // @1aa |
| |
| TMPFILENAME = saved_myTarget; // @1aa |
| if (U_FAILURE (err)) { |
| TMPFILENAME = XMLString::transcode(FILENAME); // transcode to IBM037 as backup @1aa. |
| } |
| |
| } |
| else { |
| TMPFILENAME = XMLString::transcode(FILENAME); // transcode to IBM037 as backup @1aa. |
| } |
| |
| // ArrayJanitor<char> janText((char*)saved_myTarget); @1dd |
| errno = 0; |
| FileHandle retVal = (FILE*)fopen( TMPFILENAME , "rb" ); |
| |
| if (retVal == NULL) |
| { |
| send_message((char*)TMPFILENAME,FILE_OPEN_PROBLEMS,'d'); |
| convert_errno(errno_id,errno); |
| send_message(NULL,errno_id,'d'); |
| delete [] saved_myTarget; // @1aa |
| return 0; |
| } |
| delete [] saved_myTarget; // @1aa |
| |
| return retVal; |
| } |
| |
| // If this version of openFile is ever called, need to convert the filename |
| // to job CCSID similar to what's done in the other openFile method. @1aa. |
| FileHandle XMLPlatformUtils::openFile(const char* const fileName |
| , MemoryManager* const manager) |
| { char errno_id[7]; |
| errno = 0; |
| FileHandle retVal = (FILE*)fopen( fileName , "rb" ); |
| |
| if (retVal == NULL) |
| { |
| send_message((char*)fileName,FILE_OPEN_PROBLEMS,'d'); |
| convert_errno(errno_id,errno); |
| send_message(NULL,errno_id,'d'); |
| return 0; |
| } |
| return retVal; |
| } |
| |
| FileHandle XMLPlatformUtils::openFileToWrite(const XMLCh* const fileName |
| , MemoryManager* const manager) |
| { |
| const char* tmpFileName = XMLString::transcode(fileName, manager); |
| ArrayJanitor<char> janText((char*)tmpFileName, manager); |
| |
| return openFileToWrite(tmpFileName); |
| } |
| |
| FileHandle XMLPlatformUtils::openFileToWrite(const char* const fileName |
| , MemoryManager* const manager) |
| { |
| char errno_id[7]; |
| errno = 0; |
| FileHandle retVal = (FILE*)fopen( fileName , "wb" ); |
| |
| if (retVal == NULL) |
| { |
| send_message((char*)fileName,FILE_OPEN_PROBLEMS,'d'); |
| convert_errno(errno_id,errno); |
| send_message(NULL,errno_id,'d'); |
| return 0; |
| } |
| |
| return retVal; |
| } |
| |
| unsigned int |
| XMLPlatformUtils::readFileBuffer( FileHandle theFile |
| , const unsigned int toRead |
| , XMLByte* const toFill |
| , MemoryManager* const manager) |
| { |
| size_t noOfItemsRead = fread( (void*) toFill, 1, toRead, (FILE*)theFile); |
| |
| if(ferror((FILE*)theFile)) |
| { |
| ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotReadFromFile, manager); |
| } |
| return (unsigned int)noOfItemsRead; |
| } |
| |
| void |
| XMLPlatformUtils::writeBufferToFile( FileHandle const theFile |
| , long toWrite |
| , const XMLByte* const toFlush |
| , MemoryManager* const manager) |
| { |
| if (!theFile || |
| (toWrite <= 0 ) || |
| !toFlush ) |
| return; |
| |
| const XMLByte* tmpFlush = (const XMLByte*) toFlush; |
| size_t bytesWritten = 0; |
| |
| while (true) |
| { |
| bytesWritten=fwrite(tmpFlush, sizeof(XMLByte), toWrite, (FILE*)theFile); |
| |
| if(ferror((FILE*)theFile)) |
| { |
| ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotWriteToFile, manager); |
| } |
| |
| if (bytesWritten < toWrite) //incomplete write |
| { |
| tmpFlush+=bytesWritten; |
| toWrite-=bytesWritten; |
| bytesWritten=0; |
| } |
| else |
| return; |
| } |
| |
| return; |
| } |
| |
| void XMLPlatformUtils::resetFile(FileHandle theFile |
| , MemoryManager* const manager) |
| { |
| // Seek to the start of the file |
| if (fseek((FILE*)theFile, 0, SEEK_SET) ) |
| ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotResetFile, manager); |
| } |
| |
| |
| |
| // --------------------------------------------------------------------------- |
| // XMLPlatformUtils: File system methods |
| // --------------------------------------------------------------------------- |
| |
| //------------------------- |
| //-- BEGIN realpath code -- |
| //------------------------- |
| |
| #include <limits.h> |
| #include <unistd.h> |
| #include <errno.h> |
| |
| // |
| // realpath |
| // |
| // Resolve a file name into its absolute name |
| // This function doesn't exist in the iSeries C runtime library so this partial replacement was |
| // written to handle most of its function. This implementation doesn't resolve symbolic links |
| // to their "real" paths because for the purposes of reading files the symlinks will work just |
| // fine. |
| // |
| char *realpath(const char *file_name, char *resolved_name) { |
| // Input: file_name - the name of a file or directory |
| // Output: resolved_name - file_name with a fully qualified path and all "extraneous" path stuff removed |
| // Returned value: Same as resolved_name unless there is an error in which case NULL is returned |
| // |
| // Possible errors: (no)==we don't check that |
| // EACCES Read or search permission was denied for a component of the path name. |
| // EINVAL File_name or resolved_name is a null pointer. |
| // (no) ELOOP Too many symbolic links are encountered in translating file_name. |
| // ENAMETOOLONG The length of file_name or resolved_name exceeds PATH_MAX or a path name component is longer than NAME_MAX. |
| // ENOENT The file_name parameter does not exist or points to an empty string. |
| // (no) ENOTDIR A component of the file_name prefix is not a directory. |
| // If there is an error in resolving the name the return value will be NULL (i.e., 0) and resolved_name |
| // will be changed to an empty string (a 0 will be written into its first character position) |
| |
| // Note for future expansion: "readlink" for links |
| |
| // Check for null name errors |
| if (resolved_name == NULL) { |
| errno = EINVAL; |
| return(NULL); |
| } |
| // Assumption: At this point resolved_name points to a character array large enough to hold at least PATH_MAX characters |
| if (file_name == NULL) { |
| errno = EINVAL; |
| *resolved_name = '\0'; |
| return(NULL); |
| } |
| // Assumption: At this point file_name is a valid null terminated string |
| |
| // Check for empty name error |
| if (*file_name == '\0') { |
| errno = ENOENT; |
| *resolved_name = '\0'; |
| return(NULL); |
| } |
| |
| char *from = (char*)file_name; |
| char *to = resolved_name; |
| int fromIdx=0, toIdx=0; |
| |
| if (*file_name == '/') { |
| // If file_name starts with a '/', it's an absolute path |
| // Everything's already set up properly |
| to[toIdx++] = '/'; |
| } // if |
| else { |
| // file_name doesn't start with a '/' so it is relative to the current directory |
| // Prepend the current working directory before the file name |
| getcwd(to, PATH_MAX); |
| size_t cwd_len = strlen(resolved_name); |
| // Assumption: getcwd returns a non-empty, valid, null terminated string |
| |
| // Add '/' on the cwd if needed |
| // Note: I think the only time a '/' will end the cwd is if it is just "/" |
| // but this covers otherwise just in case |
| toIdx = cwd_len; |
| if ((toIdx < PATH_MAX-1) && |
| (to[toIdx] != '/')) { |
| to[toIdx++] = '/'; |
| } // if |
| } // else |
| |
| // The target ends in a '/' at this point |
| // Skip any leading '/'s in the source |
| while (from[fromIdx] == '/') { |
| fromIdx++; |
| } // while |
| |
| // Copy from the source to the target removing extraneous "."s, "/"s, and ".."s as we go |
| // Assumption: looking ahead for characters is OK because all the string end with '/0' |
| while (from[fromIdx] != '\0' ) { |
| // Assumption - at top of loop we are either at '..', '.', or 'xxxxxxxx' (where x is any non-'/' character), each either followed by a '/' or a closing '\0' |
| // "../" => "/", also strips trailing ".." |
| if ((from[fromIdx] == '.') && |
| (from[fromIdx+1] == '.') && |
| ((from[fromIdx+2] == '/') || (from[fromIdx+2] == '\0'))) { |
| fromIdx += (from[fromIdx+2] == '\0') ? 2 : 3; |
| // Back up to the previous '/' in the target except if we are at the first '/' already |
| if (toIdx >= 2) { |
| // Back up past the current '/' |
| --toIdx; |
| // Look back until we find the previous '/' |
| while(to[toIdx-1] != '/') { |
| --toIdx; |
| } // while |
| } // if |
| } // if |
| |
| // "./" => "/", also strips trailing "." |
| else if ((from[fromIdx] == '.') && |
| ((from[fromIdx+1] == '/') || (from[fromIdx+1] == '\0'))) { |
| fromIdx += (from[fromIdx+1] == '\0') ? 1 : 2; |
| } // else if |
| |
| else { |
| // Copy the characters up to the next '/' or to the closing '\0' |
| while((from[fromIdx] != '/') && (from[fromIdx] != '\0')) { |
| // Check that the file name won't be too long (allow for the '\0' too) |
| if (toIdx >= PATH_MAX-1) { |
| errno = ENAMETOOLONG; |
| *resolved_name = '\0'; |
| return(NULL); |
| } // if |
| |
| to[toIdx++] = from[fromIdx++]; |
| } // while |
| } // else |
| |
| if (from[fromIdx] == '/') { |
| // Skip any remaining '/'s in the source |
| while (from[fromIdx] == '/') { |
| fromIdx++; |
| } // while |
| |
| // insert a '/' if there's more path to come (and room for it) |
| if (from[fromIdx] != '\0') { |
| // Check that the file name won't be too long (allow for the '\0' too) |
| if (toIdx >= PATH_MAX-1) { |
| errno = ENAMETOOLONG; |
| *resolved_name = '\0'; |
| return(NULL); |
| } // if |
| |
| to[toIdx++] = '/'; |
| } // if |
| } // if |
| |
| } // while |
| |
| // Remove a trailing '/' (except from "/") |
| if ((toIdx > 1) && |
| (to[toIdx-1] == '/')) |
| --toIdx; |
| |
| // End the string properly |
| to[toIdx] = '\0'; |
| |
| // Check if the file exists |
| if (access(resolved_name,F_OK)) { |
| errno = EACCES; |
| *resolved_name = '\0'; |
| return(NULL); |
| } // if |
| |
| // The file exists, return its name. |
| return(resolved_name); |
| } |
| |
| //----------------------- |
| //-- END realpath code -- |
| //----------------------- |
| |
| |
| |
| |
| XMLCh* XMLPlatformUtils::getFullPath(const XMLCh* const srcPath, |
| MemoryManager* const manager) |
| { |
| |
| // |
| // NOTE: THe path provided has always already been opened successfully, |
| // so we know that its not some pathological freaky path. It comes in |
| // in native format, and goes out as Unicode always |
| // |
| char* newSrc = XMLString::transcode(srcPath, manager); |
| ArrayJanitor<char> janText(newSrc, manager); |
| // Use a local buffer that is big enough for the largest legal path |
| char absPath[PATH_MAX + 1]; |
| //get the absolute path |
| char* retPath = realpath(newSrc, &absPath[0]); |
| |
| if (!retPath) |
| { |
| ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotGetBasePathName, manager); |
| } |
| return XMLString::transcode(absPath, manager); |
| |
| |
| } |
| |
| bool XMLPlatformUtils::isRelative(const XMLCh* const toCheck |
| , MemoryManager* const manager) |
| { |
| // Check for pathological case of empty path |
| if (!toCheck[0]) |
| return false; |
| |
| // |
| // If it starts with a slash, then it cannot be relative. This covers |
| // both something like "\Test\File.xml" and an NT Lan type remote path |
| // that starts with a node like "\\MyNode\Test\File.xml". |
| // |
| if (*toCheck == chForwardSlash) |
| return false; |
| |
| // Else assume its a relative path |
| return true; |
| } |
| |
| XMLCh* XMLPlatformUtils::getCurrentDirectory(MemoryManager* const manager) |
| { |
| char dirBuf[PATH_MAX + 2]; |
| char *curDir = getcwd(&dirBuf[0], PATH_MAX + 1); |
| |
| if (!curDir) |
| { |
| ThrowXMLwithMemMgr(XMLPlatformUtilsException, |
| XMLExcepts::File_CouldNotGetBasePathName, manager); |
| } |
| |
| return XMLString::transcode(curDir, manager); |
| } |
| |
| inline bool XMLPlatformUtils::isAnySlash(XMLCh c) |
| { |
| return ( chBackSlash == c || chForwardSlash == c); |
| } |
| |
| void send_message (char * text, char * messageid, char type) |
| { |
| |
| |
| short textsize; |
| char* buffer; |
| char* anchor; |
| char* id; |
| char message_id[8] = "CPF9897";/* id for raw txt |
| message */ |
| char message_file_name[21]; |
| char message_type[11] ="*DIAG ";/* send diagnostic |
| message */ |
| char call_stack[11] ="* " ;/* current callstack*/ |
| int call_stack_counter= 0;/* sent to current call stack */ |
| char message_key[4]; /* return value - not used */ |
| struct { |
| int bytes_available; |
| int bytes_used; |
| char exception_id[7]; |
| char reserved; |
| char exception_data[1]; |
| } error_code; |
| int msg_size; |
| char* msg_type; |
| error_code.bytes_available = sizeof(error_code); |
| /* check input parameters and set up the message information */ |
| if (messageid != 0) /* was a message id passed */ |
| { |
| if (strncmp(messageid,"CPF",3) && |
| strncmp(messageid,"CPE",3)) |
| strcpy(message_file_name,"QXMLMSG *LIBL "); |
| else |
| strcpy(message_file_name,"QCPFMSG QSYS "); |
| |
| |
| id = messageid; /* yes - use the id, will be |
| in QCPFMSG */ |
| |
| } |
| |
| else /* just use what we have for immediate text */ |
| { |
| id = &message_id[0]; |
| strcpy(message_file_name,"QCPFMSG QSYS "); |
| |
| } |
| if (type == 'e') /* is this the terminating exception */ |
| msg_type = "*COMP ";/* set it as completion */ |
| else /* currently all other messages are |
| diagnostics */ |
| msg_type = "*DIAG "; |
| if (text != 0) /* was a text field passed */ |
| |
| { |
| textsize = strlen(text); |
| msg_size = textsize + sizeof(short); |
| buffer = (char*)malloc(msg_size); |
| anchor = buffer; |
| memcpy(buffer, (void*)&textsize, sizeof(short)); |
| buffer +=sizeof(short); |
| memcpy(buffer, text, textsize); |
| } |
| else |
| msg_size = 0; |
| #pragma exception_handler(jsendprob, 0, _C1_ALL, _C2_ALL,_CTLA_HANDLE) |
| |
| QMHSNDPM((char *)id,&message_file_name,anchor, |
| msg_size,(char*)msg_type,(char*)&call_stack, |
| call_stack_counter,&message_key,&error_code); |
| |
| jsendprob: |
| |
| #pragma disable_handler |
| |
| return ; |
| |
| } |
| |
| void abnormal_termination(int termcode) |
| { |
| send_message(NULL,"CPF9899",'e'); /* send final exception that we have terminated*/ |
| } |
| |
| // --------------------------------------------------------------------------- |
| // XMLPlatformUtils: Timing Methods |
| // --------------------------------------------------------------------------- |
| unsigned long XMLPlatformUtils::getCurrentMillis() |
| { |
| _MI_Time mt; |
| struct timeval tv; |
| int rc; |
| |
| mattod(mt); |
| rc = Qp0zCvtToTimeval(&tv, mt, QP0Z_CVTTIME_TO_TIMESTAMP); |
| return((tv.tv_sec*1000 )+ (tv.tv_usec/1000)); |
| } |
| |
| // ----------------------------------------------------------------------- |
| // Mutex methods |
| // ----------------------------------------------------------------------- |
| |
| #if !defined (APP_NO_THREADS) |
| |
| typedef XMLHolder<pthread_mutex_t> MutexHolderType; |
| |
| static MutexHolderType* gAtomicOpMutex = 0; |
| |
| void XMLPlatformUtils::platformInit() |
| { |
| // |
| // The gAtomicOpMutex mutex needs to be created |
| // because compareAndSwap and incrementlocation and decrementlocation |
| // does not have the atomic system calls for usage |
| // Normally, mutexes are created on first use, but there is a |
| // circular dependency between compareAndExchange() and |
| // mutex creation that must be broken. |
| |
| gAtomicOpMutex = new (fgMemoryManager) MutexHolderType; |
| |
| if (pthread_mutex_init(&gAtomicOpMutex->fInstance, NULL)) { |
| delete gAtomicOpMutex; |
| gAtomicOpMutex = 0; |
| panic( PanicHandler::Panic_SystemInit ); |
| } |
| } |
| |
| class RecursiveMutex : public XMemory |
| { |
| public: |
| pthread_mutex_t mutex; |
| int recursionCount; |
| pthread_t tid; |
| MemoryManager* fManager; |
| |
| RecursiveMutex(MemoryManager* manager) : |
| fManager(manager) |
| { |
| if (pthread_mutex_init(&mutex, NULL)) |
| XMLPlatformUtils::panic(PanicHandler::Panic_MutexErr); |
| recursionCount = 0; |
| tid.reservedHiId = 0; |
| tid.reservedLoId = 0; |
| tid.reservedHandle = 0; |
| } |
| |
| ~RecursiveMutex() { |
| if (pthread_mutex_destroy(&mutex)) |
| ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::Mutex_CouldNotDestroy, fManager); |
| } |
| |
| void lock() { |
| if (pthread_equal(tid, pthread_self())) |
| { |
| recursionCount++; |
| return; |
| } |
| if (pthread_mutex_lock(&mutex) != 0) |
| XMLPlatformUtils::panic(PanicHandler::Panic_MutexErr); |
| tid = pthread_self(); |
| recursionCount = 1; |
| } |
| |
| |
| void unlock() { |
| if (--recursionCount > 0) |
| return; |
| |
| if (pthread_mutex_unlock(&mutex) != 0) |
| XMLPlatformUtils::panic(PanicHandler::Panic_MutexErr); |
| tid.reservedHandle= 0; |
| tid.reservedHiId = 0; |
| tid.reservedLoId = 0; |
| } |
| }; |
| |
| void* XMLPlatformUtils::makeMutex(MemoryManager* manager) |
| { |
| return new (manager) RecursiveMutex(manager); |
| } |
| |
| |
| void XMLPlatformUtils::closeMutex(void* const mtxHandle) |
| { |
| if (mtxHandle == NULL) |
| return; |
| RecursiveMutex *rm = (RecursiveMutex *)mtxHandle; |
| delete rm; |
| } |
| |
| |
| void XMLPlatformUtils::lockMutex(void* const mtxHandle) |
| { |
| if (mtxHandle == NULL) |
| return; |
| RecursiveMutex *rm = (RecursiveMutex *)mtxHandle; |
| rm->lock(); |
| } |
| |
| void XMLPlatformUtils::unlockMutex(void* const mtxHandle) |
| { |
| if (mtxHandle == NULL) |
| return; |
| RecursiveMutex *rm = (RecursiveMutex *)mtxHandle; |
| rm->unlock(); |
| } |
| |
| // ----------------------------------------------------------------------- |
| // Miscellaneous synchronization methods |
| // ----------------------------------------------------------------------- |
| //atomic system calls in Solaris is only restricted to kernel libraries |
| //So, to make operations thread safe we implement static mutex and lock |
| //the atomic operations. It makes the process slow but what's the alternative! |
| void* XMLPlatformUtils::compareAndSwap ( void** toFill , |
| const void* const newValue , |
| const void* const toCompare) |
| { |
| //return ((void*)cas32( (uint32_t*)toFill, (uint32_t)toCompare, (uint32_t)newValue) ); |
| // the below calls are temporarily made till the above functions are part of user library |
| // Currently its supported only in the kernel mode |
| |
| if (pthread_mutex_lock( &gAtomicOpMutex->fInstance)) |
| panic(PanicHandler::Panic_SynchronizationErr); |
| |
| void *retVal = *toFill; |
| if (*toFill == toCompare) |
| *toFill = (void *)newValue; |
| |
| if (pthread_mutex_unlock( &gAtomicOpMutex->fInstance)) |
| panic(PanicHandler::Panic_SynchronizationErr); |
| |
| return retVal; |
| } |
| |
| int XMLPlatformUtils::atomicIncrement(int &location) |
| { |
| int current = location; |
| int new_loc = current+1; |
| |
| while (_CMPSWP(¤t, |
| &location, |
| new_loc) == 0) |
| new_loc = current+1; |
| int tmp = new_loc; |
| |
| return tmp; |
| } |
| int XMLPlatformUtils::atomicDecrement(int &location) |
| { |
| |
| int current = location; |
| int new_loc = current-1; |
| |
| while (_CMPSWP(¤t, |
| &location, |
| new_loc) == 0) |
| new_loc = current-1; |
| int tmp = new_loc; |
| |
| return tmp; |
| } |
| |
| |
| #else // #if !defined (APP_NO_THREADS) |
| |
| void XMLPlatformUtils::platformInit() |
| { |
| // do nothing |
| } |
| |
| void XMLPlatformUtils::closeMutex(void* const) |
| { |
| } |
| |
| void XMLPlatformUtils::lockMutex(void* constmanager) |
| { |
| } |
| |
| void* XMLPlatformUtils::makeMutex(MemoryManager*) |
| { |
| return 0; |
| } |
| |
| void XMLPlatformUtils::unlockMutex(void* const) |
| { |
| } |
| |
| void* XMLPlatformUtils::compareAndSwap ( void** toFill, |
| const void* const newValue, |
| const void* const toCompare) |
| { |
| void *retVal = *toFill; |
| if (*toFill == toCompare) |
| *toFill = (void *)newValue; |
| return retVal; |
| } |
| |
| int XMLPlatformUtils::atomicIncrement(int &location) |
| { |
| return ++location; |
| } |
| |
| int XMLPlatformUtils::atomicDecrement(int &location) |
| { |
| return --location; |
| } |
| |
| #endif // APP_NO_THREADS |
| |
| |
| /* |
| * convert the errno value to a cpf message identifier by converting the |
| * error to its decimal equivalent and appending "CPE" to the front |
| * note that the caller passes the storage for the message id as a parm |
| */ |
| void convert_errno(char* errno_id,int errnum) |
| { |
| sprintf(errno_id,"CPE%d04" ,errnum ); |
| return; |
| } |
| |
| FileHandle XMLPlatformUtils::openStdInHandle(MemoryManager* const manager) |
| { |
| return (FileHandle)fdopen(dup(0), "r"); |
| } |
| |
| void XMLPlatformUtils::platformTerm() |
| { |
| #if !defined (APP_NO_THREADS) |
| pthread_mutex_destroy(&gAtomicOpMutex->fInstance); |
| delete gAtomicOpMutex; |
| gAtomicOpMutex = 0; |
| #endif |
| |
| #if defined (XML_USE_ICONV400_TRANSCODER) |
| cleanupDefaultConverter(); |
| #endif |
| } |
| |
| #include <xercesc/util/LogicalPath.c> |
| |
| XERCES_CPP_NAMESPACE_END |