static int init_ssl_socket( pn_ssl_t *ssl ) { if (ssl->ssl) return 0; if (!ssl->domain) return -1; ssl->ssl = SSL_new(ssl->domain->ctx); if (!ssl->ssl) { _log_error( "SSL socket setup failure.\n" ); return -1; } // store backpointer to pn_ssl_t in SSL object: SSL_set_ex_data(ssl->ssl, ssl_ex_data_index, ssl); #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME if (ssl->peer_hostname && ssl->domain->mode == PN_SSL_MODE_CLIENT) { SSL_set_tlsext_host_name(ssl->ssl, ssl->peer_hostname); } #endif // restore session, if available if (ssl->session_id) { pn_ssl_session_t *ssn = ssn_cache_find( ssl->domain, ssl->session_id ); if (ssn) { _log( ssl, "Restoring previous session id=%s\n", ssn->id ); int rc = SSL_set_session( ssl->ssl, ssn->session ); if (rc != 1) { _log( ssl, "Session restore failed, id=%s\n", ssn->id ); } LL_REMOVE( ssl->domain, ssn_cache, ssn ); ssl_session_free( ssn ); } } // now layer a BIO over the SSL socket ssl->bio_ssl = BIO_new(BIO_f_ssl()); if (!ssl->bio_ssl) { _log_error( "BIO setup failure.\n" ); return -1; } (void)BIO_set_ssl(ssl->bio_ssl, ssl->ssl, BIO_NOCLOSE); // create the "lower" BIO "pipe", and attach it below the SSL layer if (!BIO_new_bio_pair(&ssl->bio_ssl_io, 0, &ssl->bio_net_io, 0)) { _log_error( "BIO setup failure.\n" ); return -1; } SSL_set_bio(ssl->ssl, ssl->bio_ssl_io, ssl->bio_ssl_io); if (ssl->domain->mode == PN_SSL_MODE_SERVER) { SSL_set_accept_state(ssl->ssl); BIO_set_ssl_mode(ssl->bio_ssl, 0); // server mode _log( ssl, "Server SSL socket created.\n" ); } else { // client mode SSL_set_connect_state(ssl->ssl); BIO_set_ssl_mode(ssl->bio_ssl, 1); // client mode _log( ssl, "Client SSL socket created.\n" ); } return 0; }
int pn_ssl_domain_set_peer_authentication(pn_ssl_domain_t *domain, const pn_ssl_verify_mode_t mode, const char *trusted_CAs) { if (!domain) return -1; switch (mode) { case PN_SSL_VERIFY_PEER: case PN_SSL_VERIFY_PEER_NAME: if (!domain->has_ca_db) { _log_error("Error: cannot verify peer without a trusted CA configured.\n" " Use pn_ssl_domain_set_trusted_ca_db()\n"); return -1; } if (domain->mode == PN_SSL_MODE_SERVER) { // openssl requires that server connections supply a list of trusted CAs which is // sent to the client if (!trusted_CAs) { _log_error("Error: a list of trusted CAs must be provided.\n"); return -1; } if (!domain->has_certificate) { _log_error("Error: Server cannot verify peer without configuring a certificate.\n" " Use pn_ssl_domain_set_credentials()\n"); } if (domain->trusted_CAs) free(domain->trusted_CAs); domain->trusted_CAs = pn_strdup( trusted_CAs ); STACK_OF(X509_NAME) *cert_names; cert_names = SSL_load_client_CA_file( domain->trusted_CAs ); if (cert_names != NULL) SSL_CTX_set_client_CA_list(domain->ctx, cert_names); else { _log_error("Error: Unable to process file of trusted CAs: %s\n", trusted_CAs); return -1; } } SSL_CTX_set_verify( domain->ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_callback); #if (OPENSSL_VERSION_NUMBER < 0x00905100L) SSL_CTX_set_verify_depth(domain->ctx, 1); #endif break; case PN_SSL_ANONYMOUS_PEER: // hippie free love mode... :) SSL_CTX_set_verify( domain->ctx, SSL_VERIFY_NONE, NULL ); break; default: _log_error( "Invalid peer authentication mode given.\n" ); return -1; } domain->verify_mode = mode; return 0; }
int pn_ssl_domain_set_trusted_ca_db(pn_ssl_domain_t *domain, const char *certificate_db) { if (!domain) return -1; // certificates can be either a file or a directory, which determines how it is passed // to SSL_CTX_load_verify_locations() struct stat sbuf; if (stat( certificate_db, &sbuf ) != 0) { _log_error("stat(%s) failed: %s\n", certificate_db, strerror(errno)); return -1; } const char *file; const char *dir; if (S_ISDIR(sbuf.st_mode)) { dir = certificate_db; file = NULL; } else { dir = NULL; file = certificate_db; } if (SSL_CTX_load_verify_locations( domain->ctx, file, dir ) != 1) { _log_ssl_error( "SSL_CTX_load_verify_locations( %s ) failed\n", certificate_db); return -1; } domain->has_ca_db = true; return 0; }
static void _execute_correct(const gchar *testcase, Checks checks, const gchar *user_data) { if (!_execute(testcase, checks, user_data)) { _log_error("expected the subject to succeed, but it failed"); _tests_failed = 1; } }
static void _execute_failing(const gchar *testcase, Checks checks, const gchar *user_data) { if (_execute(testcase, checks, user_data)) { _log_error("expected the subject to fail, but it succeeded"); _tests_failed = 1; } }
int pn_ssl_domain_allow_unsecured_client(pn_ssl_domain_t *domain) { if (!domain) return -1; if (domain->mode != PN_SSL_MODE_SERVER) { _log_error("Cannot permit unsecured clients - not a server.\n"); return -1; } domain->allow_unsecured = true; return 0; }
// log an error and dump the SSL error stack static void _log_ssl_error( const char *fmt, ...) { char buf[128]; // see "man ERR_error_string_n()" va_list ap; if (fmt) { va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); } unsigned long err = ERR_get_error(); while (err) { ERR_error_string_n(err, buf, sizeof(buf)); _log_error("%s\n", buf); err = ERR_get_error(); } }
SEXP _est_gen_Q_C( SEXP spYdelt, SEXP spZ, SEXP spX, SEXP spMaf, SEXP spParNull) { // int nUsed0, nTotal0; // CFmVector::StatCache( &nTotal0, &nUsed0 ); // int nUsed1, nTotal1; // CFmMatrix::StatCache( &nTotal1, &nUsed1 ); // Rprintf( "Enter C Range, Vec.count=%d, Mat.count=%d\n", nTotal0, nTotal1); CFmMatrix* pFmYDelt = getMatrixData(spYdelt); CFmMatrix* pFmZ = getMatrixData(spZ); CFmMatrix* pFmX = getMatrixData(spX); CFmVector* pFmMaf = getVectorData(spMaf); CFmVector* pFmParNull = getVectorData(spParNull); SEXP ret; try { ret = Xest_gen_Q_C( pFmYDelt, pFmZ, pFmX, pFmMaf, pFmParNull); } catch(const char* str) { _log_error( _HI_, "Exception=%s", str); return( R_NilValue ); } destroy( pFmYDelt ); destroy( pFmZ ); destroy( pFmX ); destroy( pFmMaf ); destroy( pFmParNull ); // CFmVector::StatCache( &nTotal0, &nUsed0 ); // CFmMatrix::StatCache( &nTotal1, &nUsed1 ); // Rprintf( "Leave C Range, Vec.count=%d, Mat.count=%d\n", nTotal0, nTotal1); return(ret); }
// take data from the network, and pass it into SSL. Attempt to read decrypted data from // SSL socket and pass it to the application. static ssize_t process_input_ssl( pn_io_layer_t *io_layer, const char *input_data, size_t available) { pn_ssl_t *ssl = (pn_ssl_t *)io_layer->context; if (ssl->ssl == NULL && init_ssl_socket(ssl)) return PN_ERR; _log( ssl, "process_input_ssl( data size=%d )\n",available ); ssize_t consumed = 0; bool work_pending; bool shutdown_input = (available == 0); // caller is closed do { work_pending = false; // Write to network bio as much as possible, consuming bytes/available if (available > 0) { int written = BIO_write( ssl->bio_net_io, input_data, available ); if (written > 0) { input_data += written; available -= written; consumed += written; ssl->read_blocked = false; work_pending = (available > 0); _log( ssl, "Wrote %d bytes to BIO Layer, %d left over\n", written, available ); } } else if (shutdown_input) { // lower layer (caller) has closed. Close the WRITE side of the BIO. This will cause // an EOF to be passed to SSL once all pending inbound data has been consumed. _log( ssl, "Lower layer closed - shutting down BIO write side\n"); (void)BIO_shutdown_wr( ssl->bio_net_io ); shutdown_input = false; } // Read all available data from the SSL socket if (!ssl->ssl_closed && ssl->in_count < ssl->in_size) { int read = BIO_read( ssl->bio_ssl, &ssl->inbuf[ssl->in_count], ssl->in_size - ssl->in_count ); if (read > 0) { _log( ssl, "Read %d bytes from SSL socket for app\n", read ); _log_clear_data( ssl, &ssl->inbuf[ssl->in_count], read ); ssl->in_count += read; work_pending = true; } else { if (!BIO_should_retry(ssl->bio_ssl)) { int reason = SSL_get_error( ssl->ssl, read ); switch (reason) { case SSL_ERROR_ZERO_RETURN: // SSL closed cleanly _log(ssl, "SSL connection has closed\n"); start_ssl_shutdown(ssl); // KAG: not sure - this may not be necessary ssl->ssl_closed = true; break; default: // unexpected error return (ssize_t)ssl_failed(ssl); } } else { if (BIO_should_write( ssl->bio_ssl )) { ssl->write_blocked = true; _log(ssl, "Detected write-blocked\n"); } if (BIO_should_read( ssl->bio_ssl )) { ssl->read_blocked = true; _log(ssl, "Detected read-blocked\n"); } } } } // write incoming data to app layer if (!ssl->app_input_closed) { char *data = ssl->inbuf; if (ssl->in_count > 0 || ssl->ssl_closed) { /* if ssl_closed, send 0 count */ pn_io_layer_t *io_next = ssl->io_layer->next; ssize_t consumed = io_next->process_input( io_next, data, ssl->in_count); if (consumed > 0) { ssl->in_count -= consumed; data += consumed; work_pending = true; _log( ssl, "Application consumed %d bytes from peer\n", (int) consumed ); } else if (consumed < 0) { _log(ssl, "Application layer closed its input, error=%d (discarding %d bytes)\n", (int) consumed, (int)ssl->in_count); ssl->in_count = 0; // discard any pending input ssl->app_input_closed = consumed; if (ssl->app_output_closed && ssl->out_count == 0) { // both sides of app closed, and no more app output pending: start_ssl_shutdown(ssl); } } else { // app did not consume any bytes, must be waiting for a full frame if (ssl->in_count == ssl->in_size) { // but the buffer is full, not enough room for a full frame. // can we grow the buffer? uint32_t max_frame = pn_transport_get_max_frame(ssl->transport); if (!max_frame) max_frame = ssl->in_size * 2; // no limit if (ssl->in_size < max_frame) { // no max frame limit - grow it. char *newbuf = (char *)malloc( max_frame ); if (newbuf) { ssl->in_size *= max_frame; memmove( newbuf, ssl->inbuf, ssl->in_count ); free( ssl->inbuf ); ssl->inbuf = newbuf; } work_pending = true; // can we get more input? } else { // can't gather any more input, but app needs more? // This is a bug - since SSL can buffer up to max-frame, // the application _must_ have enough data to process. If // this is an oversized frame, the app _must_ handle it // by returning an error code to SSL. _log_error("Error: application unable to consume input.\n"); } } } } if (ssl->in_count > 0 && data != ssl->inbuf) memmove( ssl->inbuf, data, ssl->in_count ); } } while (work_pending); //_log(ssl, "ssl_closed=%d in_count=%d app_input_closed=%d app_output_closed=%d\n", // ssl->ssl_closed, ssl->in_count, ssl->app_input_closed, ssl->app_output_closed ); // PROTON-82: Instead, close the input side as soon as we've completed enough of the SSL // shutdown handshake to send the close_notify. We're not requiring the response, as // some implementations never reply. // --- // tell transport our input side is closed if the SSL socket cannot be read from any // longer, AND any pending input has been written up to the application (or the // application is closed) //if (ssl->ssl_closed && ssl->app_input_closed) { // consumed = ssl->app_input_closed; //} if (ssl->app_input_closed && (SSL_get_shutdown(ssl->ssl) & SSL_SENT_SHUTDOWN) ) { consumed = ssl->app_input_closed; ssl->io_layer->process_input = process_input_done; } _log(ssl, "process_input_ssl() returning %d\n", (int) consumed); return consumed; }
pn_ssl_domain_t *pn_ssl_domain( pn_ssl_mode_t mode ) { if (!ssl_initialized) { ssl_initialized = 1; SSL_library_init(); SSL_load_error_strings(); OpenSSL_add_all_algorithms(); ssl_ex_data_index = SSL_get_ex_new_index( 0, (void *) "org.apache.qpid.proton.ssl", NULL, NULL, NULL); } pn_ssl_domain_t *domain = (pn_ssl_domain_t *) calloc(1, sizeof(pn_ssl_domain_t)); if (!domain) return NULL; domain->ref_count = 1; domain->mode = mode; switch(mode) { case PN_SSL_MODE_CLIENT: domain->ctx = SSL_CTX_new(TLSv1_client_method()); if (!domain->ctx) { _log_ssl_error( "Unable to initialize OpenSSL context.\n"); free(domain); return NULL; } break; case PN_SSL_MODE_SERVER: domain->ctx = SSL_CTX_new(SSLv23_server_method()); if (!domain->ctx) { _log_ssl_error("Unable to initialize OpenSSL context.\n"); free(domain); return NULL; } SSL_CTX_set_options(domain->ctx, SSL_OP_NO_SSLv2); // v2 is insecure break; default: _log_error("Invalid valid for pn_ssl_mode_t: %d\n", mode); free(domain); return NULL; } // by default, allow anonymous ciphers so certificates are not required 'out of the box' if (!SSL_CTX_set_cipher_list( domain->ctx, CIPHERS_ANONYMOUS )) { _log_ssl_error("Failed to set cipher list to %s\n", CIPHERS_ANONYMOUS); pn_ssl_domain_free(domain); return NULL; } // ditto: by default do not authenticate the peer (can be done by SASL). if (pn_ssl_domain_set_peer_authentication( domain, PN_SSL_ANONYMOUS_PEER, NULL )) { pn_ssl_domain_free(domain); return NULL; } DH *dh = get_dh2048(); if (dh) { SSL_CTX_set_tmp_dh(domain->ctx, dh); DH_free(dh); SSL_CTX_set_options(domain->ctx, SSL_OP_SINGLE_DH_USE); } return domain; }
// Certificate chain verification callback: return 1 if verified, // 0 if remote cannot be verified (fail handshake). // static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) { if (!preverify_ok || X509_STORE_CTX_get_error_depth(ctx) != 0) // already failed, or not at peer cert in chain return preverify_ok; X509 *cert = X509_STORE_CTX_get_current_cert(ctx); SSL *ssn = (SSL *) X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); if (!ssn) { _log_error("Error: unexpected error - SSL session info not available for peer verify!\n"); return 0; // fail connection } pn_ssl_t *ssl = (pn_ssl_t *)SSL_get_ex_data(ssn, ssl_ex_data_index); if (!ssl) { _log_error("Error: unexpected error - SSL context info not available for peer verify!\n"); return 0; // fail connection } if (ssl->domain->verify_mode != PN_SSL_VERIFY_PEER_NAME) return preverify_ok; if (!ssl->peer_hostname) { _log_error("Error: configuration error: PN_SSL_VERIFY_PEER_NAME configured, but no peer hostname set!\n"); return 0; // fail connection } _log( ssl, "Checking identifying name in peer cert against '%s'\n", ssl->peer_hostname); bool matched = false; /* first check any SubjectAltName entries, as per RFC2818 */ GENERAL_NAMES *sans = (GENERAL_NAMES *) X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); if (sans) { int name_ct = sk_GENERAL_NAME_num( sans ); int i; for (i = 0; !matched && i < name_ct; ++i) { GENERAL_NAME *name = sk_GENERAL_NAME_value( sans, i ); if (name->type == GEN_DNS) { ASN1_STRING *asn1 = name->d.dNSName; if (asn1 && asn1->data && asn1->length) { unsigned char *str; int len = ASN1_STRING_to_UTF8( &str, asn1 ); if (len >= 0) { _log( ssl, "SubjectAltName (dns) from peer cert = '%.*s'\n", len, str ); matched = match_dns_pattern( ssl->peer_hostname, (const char *)str, len ); OPENSSL_free( str ); } } } } GENERAL_NAMES_free( sans ); } /* if no general names match, try the CommonName from the subject */ X509_NAME *name = X509_get_subject_name(cert); int i = -1; while (!matched && (i = X509_NAME_get_index_by_NID(name, NID_commonName, i)) >= 0) { X509_NAME_ENTRY *ne = X509_NAME_get_entry(name, i); ASN1_STRING *name_asn1 = X509_NAME_ENTRY_get_data(ne); if (name_asn1) { unsigned char *str; int len = ASN1_STRING_to_UTF8( &str, name_asn1); if (len >= 0) { _log( ssl, "commonName from peer cert = '%.*s'\n", len, str ); matched = match_dns_pattern( ssl->peer_hostname, (const char *)str, len ); OPENSSL_free(str); } } } if (!matched) { _log( ssl, "Error: no name matching %s found in peer cert - rejecting handshake.\n", ssl->peer_hostname); preverify_ok = 0; #ifdef X509_V_ERR_APPLICATION_VERIFICATION X509_STORE_CTX_set_error( ctx, X509_V_ERR_APPLICATION_VERIFICATION ); #endif } else { _log( ssl, "Name from peer cert matched - peer is valid.\n" ); } return preverify_ok; }
/* Process each event emitted by the protocol engine */ static void dispatcher(pn_handler_t *handler, pn_event_t *event, pn_event_type_t type) { protocolState_t *ps = PROTOCOL_STATE(handler); const configSettings_t *cfg = ps->config; //DBGPRINTF("omamqp1: Event received: %s\n", pn_event_type_name(type)); switch (type) { case PN_LINK_REMOTE_OPEN: DBGPRINTF("omamqp1: Message bus opened link.\n"); break; case PN_DELIVERY: // has the message been delivered to the message bus? if (ps->delivery) { assert(ps->delivery == pn_event_delivery(event)); if (pn_delivery_updated(ps->delivery)) { rsRetVal result = RS_RET_IDLE; uint64_t rs = pn_delivery_remote_state(ps->delivery); switch (rs) { case PN_ACCEPTED: DBGPRINTF("omamqp1: Message ACCEPTED by message bus\n"); result = RS_RET_OK; break; case PN_REJECTED: dbgprintf("omamqp1: message bus rejected log message: invalid message - dropping\n"); // message bus considers this a 'bad message'. Cannot be redelivered. // Likely a configuration error. Drop the message by returning OK result = RS_RET_OK; break; case PN_RELEASED: case PN_MODIFIED: // the message bus cannot accept the message. This may be temporary - retry // up to maxRetries before dropping if (++ps->retries >= cfg->maxRetries) { dbgprintf("omamqp1: message bus failed to accept message - dropping\n"); result = RS_RET_OK; } else { dbgprintf("omamqp1: message bus cannot accept message, retrying\n"); result = RS_RET_SUSPENDED; } break; case PN_RECEIVED: // not finished yet, wait for next delivery update break; default: // no other terminal states defined, so ignore anything else dbgprintf("omamqp1: unknown delivery state=0x%lX, assuming message accepted\n", (unsigned long) pn_delivery_remote_state(ps->delivery)); result = RS_RET_OK; break; } if (result != RS_RET_IDLE) { // the command is complete threadIPC_t *ipc = ps->ipc; pthread_mutex_lock(&ipc->lock); assert(ipc->command == COMMAND_SEND); ipc->result = result; ipc->command = COMMAND_DONE; pthread_cond_signal(&ipc->condition); pthread_mutex_unlock(&ipc->lock); pn_delivery_settle(ps->delivery); ps->delivery = NULL; if (result == RS_RET_OK) { ps->retries = 0; } } } } break; case PN_CONNECTION_BOUND: if (!cfg->bDisableSASL) { // force use of SASL, even allowing PLAIN authentication pn_sasl_t *sasl = pn_sasl(pn_event_transport(event)); #if PN_VERSION_MAJOR == 0 && PN_VERSION_MINOR >= 10 pn_sasl_set_allow_insecure_mechs(sasl, true); #else // proton version <= 0.9 only supports PLAIN authentication const char *user = cfg->username ? (char *)cfg->username : pn_url_get_username(cfg->url); if (user) { pn_sasl_plain(sasl, user, (cfg->password ? (char *) cfg->password : pn_url_get_password(cfg->url))); } #endif } if (cfg->idleTimeout) { // configured as seconds, set as milliseconds pn_transport_set_idle_timeout(pn_event_transport(event), cfg->idleTimeout * 1000); } break; case PN_CONNECTION_UNBOUND: DBGPRINTF("omamqp1: cleaning up connection resources\n"); pn_connection_release(pn_event_connection(event)); ps->conn = NULL; ps->sender = NULL; ps->delivery = NULL; break; case PN_TRANSPORT_ERROR: { // TODO: if auth failure, does it make sense to retry??? pn_transport_t *tport = pn_event_transport(event); pn_condition_t *cond = pn_transport_condition(tport); if (pn_condition_is_set(cond)) { _log_error("transport failure", cond); } dbgprintf("omamqp1: network transport failed, reconnecting...\n"); // the protocol thread will attempt to reconnect if it is not // being shut down } break; default: break; } }
// this function reads a file for "," separated values and creates a matrix object from it int CFmDataFrame::Load(const char* filename, bool bRowName, bool bColName) { _log_debug(_HI_, "CFmDataFrame::Load:%s, bRowName=%d, bColName=%d", filename, bRowName, bColName); FILE* fp = fopen( filename, "rt"); if (fp==NULL) { _log_error(_HI_, "The file can not be opened(%s)", filename); return(ERR_OPEN_FILE); } char aLine[MAX_LINE_WIDTH+1]={0}; if( fgets( aLine, MAX_LINE_WIDTH, fp ) == NULL) { _log_error( _HI_, "Failed to read a line (%s)", filename); fclose(fp); return(ERR_READ_FILE); } CFmVectorStr vctRowNames(0); CFmVectorStr vctColNames(0); int col_size = 0; // count how many elements in the first lines const char seps1[] = ",\t\n\r"; char* running = Strdup (aLine); char* runnptr = running; char* token = _strsep((char**)&running, seps1 ); while(token) { if(strlen(token)!=0) { vctColNames.Put( token); col_size++; } token = _strsep( (char**)&running, seps1 ); } Free(runnptr); _log_debug(_HI_, "CFmDataFrame::Load: col_size: %d", col_size); CFmVector tmpRow(col_size, 0.0); if (bRowName && !bColName) tmpRow.Resize(col_size-1); int nMaxRows = 20; int nMaxCols = tmpRow.GetLength(); m_nNumCols = tmpRow.GetLength(); m_nNumRows = 0; AllocMemory( nMaxRows, nMaxCols ); if (!bColName) { if (!bRowName) { m_nNumCols = col_size; for (int i=0; i<col_size; i++) Set(0, i, vctColNames[i]); } else { m_nNumCols = col_size-1; for (int i=1; i<col_size+1; i++) Set(0, i-1, vctColNames[i]); vctRowNames.Put( vctColNames[0] ); } m_nNumRows++; } CFmVectorStr vctTmpRow(0); while(!feof(fp)) { if( fgets( aLine, MAX_LINE_WIDTH, fp ) == NULL) break; char* running = Strdup (aLine); vctTmpRow.Reset(0); char* token = _strsep( &running, seps1 ); int nNonEmty = 0; while(token) { if (strlen(token)!=0 && strncmp(token, "\n", 1)!=0 && strncmp(token, "\r", 1)!=0 && strncmp(token, "\t", 1)!=0) nNonEmty ++; vctTmpRow.Put(token); token = _strsep( &running, seps1 ); } Free(running); if (nNonEmty==0) break; m_nNumRows++; if (m_nNumRows >= m_nMaxRows ) AllocMemory( m_nNumRows+20, m_nMaxCols ); if (!bRowName) { for (int i=0; i<col_size && i<vctTmpRow.GetLength(); i++) Set( m_nNumRows-1, i, vctTmpRow[i] ); } else { for (int i=1; i<col_size+1 && i<vctTmpRow.GetLength(); i++) { Set( m_nNumRows-1, i-1, vctTmpRow[i] ); } vctRowNames.Put( vctTmpRow[0]); } } fclose(fp); CFmNewTemp refNew; if (bRowName) m_pRowNames = new (refNew) CFmVectorStr( &vctRowNames ); if (bColName) m_pColNames = new (refNew) CFmVectorStr( &vctColNames ); _log_debug(_HI_, "CFmDataFrame::Load:%d,%d", m_nNumRows, m_nNumCols); return(0); }