+ ZEBRA_RES r = ZEBRA_OK;
+ int i, fd;
+ char gprefix[128];
+ char ext[128];
+ char ext_res[128];
+ const char *original_record_type = 0;
+ RecType recType;
+ void *recTypeClientData;
+ struct ZebraRecStream stream, *streamp;
+
+ zebra_init_log_level();
+
+ if (!zh->m_group || !*zh->m_group)
+ *gprefix = '\0';
+ else
+ sprintf(gprefix, "%s.", zh->m_group);
+
+ yaz_log(log_level_extract, "zebra_extract_file %s", fname);
+
+ /* determine file extension */
+ *ext = '\0';
+ for (i = strlen(fname); --i >= 0; )
+ if (fname[i] == '/')
+ break;
+ else if (fname[i] == '.')
+ {
+ strcpy(ext, fname+i+1);
+ break;
+ }
+ /* determine file type - depending on extension */
+ original_record_type = zh->m_record_type;
+ if (!zh->m_record_type)
+ {
+ sprintf(ext_res, "%srecordType.%s", gprefix, ext);
+ zh->m_record_type = res_get(zh->res, ext_res);
+ }
+ if (!zh->m_record_type)
+ {
+ check_log_limit(zh);
+ if (zh->records_processed + zh->records_skipped
+ < zh->m_file_verbose_limit)
+ yaz_log(YLOG_LOG, "? %s", fname);
+ zh->records_skipped++;
+ return 0;
+ }
+ /* determine match criteria */
+ if (!zh->m_record_id)
+ {
+ sprintf(ext_res, "%srecordId.%s", gprefix, ext);
+ zh->m_record_id = res_get(zh->res, ext_res);
+ }
+
+ if (!(recType =
+ recType_byName(zh->reg->recTypes, zh->res, zh->m_record_type,
+ &recTypeClientData)))
+ {
+ yaz_log(YLOG_WARN, "No such record type: %s", zh->m_record_type);
+ return ZEBRA_FAIL;
+ }
+
+ switch(recType->version)
+ {
+ case 0:
+ break;
+ default:
+ yaz_log(YLOG_WARN, "Bad filter version: %s", zh->m_record_type);
+ }
+ if (sysno && (action == action_delete || action == action_a_delete))
+ {
+ streamp = 0;
+ }
+ else
+ {
+ char full_rep[1024];
+
+ if (zh->path_reg && !yaz_is_abspath(fname))
+ {
+ strcpy(full_rep, zh->path_reg);
+ strcat(full_rep, "/");
+ strcat(full_rep, fname);
+ }
+ else
+ strcpy(full_rep, fname);
+
+ if ((fd = open(full_rep, O_BINARY|O_RDONLY)) == -1)
+ {
+ yaz_log(YLOG_WARN|YLOG_ERRNO, "open %s", full_rep);
+ zh->m_record_type = original_record_type;
+ return ZEBRA_FAIL;
+ }
+ streamp = &stream;
+ zebra_create_stream_fd(streamp, fd, 0);
+ }
+ r = zebra_extract_records_stream(zh, streamp,
+ action,
+ zh->m_record_type,
+ sysno,
+ 0, /*match_criteria */
+ fname,
+ recType, recTypeClientData);
+ if (streamp)
+ stream.destroy(streamp);
+ zh->m_record_type = original_record_type;
+ return r;
+}
+
+/*
+ If sysno is provided, then it's used to identify the reocord.
+ If not, and match_criteria is provided, then sysno is guessed
+ If not, and a record is provided, then sysno is got from there
+
+ */
+
+ZEBRA_RES zebra_buffer_extract_record(ZebraHandle zh,
+ const char *buf, size_t buf_size,
+ enum zebra_recctrl_action_t action,
+ const char *recordType,
+ zint *sysno,
+ const char *match_criteria,
+ const char *fname)
+{
+ struct ZebraRecStream stream;
+ ZEBRA_RES res;
+ void *clientData;
+ RecType recType = 0;
+
+ if (recordType && *recordType)
+ {
+ yaz_log(log_level_extract,
+ "Record type explicitly specified: %s", recordType);
+ recType = recType_byName(zh->reg->recTypes, zh->res, recordType,
+ &clientData);
+ }
+ else
+ {
+ if (!(zh->m_record_type))
+ {
+ yaz_log(YLOG_WARN, "No such record type defined");
+ return ZEBRA_FAIL;
+ }
+ yaz_log(log_level_extract, "Get record type from rgroup: %s",
+ zh->m_record_type);
+ recType = recType_byName(zh->reg->recTypes, zh->res,
+ zh->m_record_type, &clientData);
+ recordType = zh->m_record_type;
+ }
+
+ if (!recType)
+ {
+ yaz_log(YLOG_WARN, "No such record type: %s", recordType);
+ return ZEBRA_FAIL;
+ }
+
+ zebra_create_stream_mem(&stream, buf, buf_size);
+
+ res = zebra_extract_records_stream(zh, &stream,
+ action,
+ recordType,
+ sysno,
+ match_criteria,
+ fname,
+ recType, clientData);
+ stream.destroy(&stream);
+ return res;
+}
+
+static ZEBRA_RES zebra_extract_record_stream(ZebraHandle zh,
+ struct ZebraRecStream *stream,
+ enum zebra_recctrl_action_t action,
+ const char *recordType,
+ zint *sysno,
+ const char *match_criteria,
+ const char *fname,
+ RecType recType,
+ void *recTypeClientData,
+ int *more)
+
+{
+ zint sysno0 = 0;
+ RecordAttr *recordAttr;