+ while ((gr->spreadsheet.sheets[n].last_col == -1)
+ &&
+ (1 == (ret = xmlTextReaderRead (gr->msd.xtr))))
+ {
+ process_node (gr, &gr->msd);
+ }
+
+ assert (n < gr->n_sheets);
+ return create_cell_range (
+ gr->spreadsheet.sheets[n].first_col,
+ gr->spreadsheet.sheets[n].first_row,
+ gr->spreadsheet.sheets[n].last_col,
+ gr->spreadsheet.sheets[n].last_row);
+}
+
+
+static unsigned int
+gnumeric_get_sheet_n_rows (struct spreadsheet *s, int n)
+{
+ struct gnumeric_reader *gr = (struct gnumeric_reader *) s;
+
+ while ((gr->spreadsheet.sheets[n].last_col == -1)
+ &&
+ (1 == xmlTextReaderRead (gr->msd.xtr)))
+ {
+ process_node (gr, &gr->msd);
+ }
+
+ assert (n < gr->n_sheets);
+ return gr->spreadsheet.sheets[n].last_row + 1;
+}
+
+static unsigned int
+gnumeric_get_sheet_n_columns (struct spreadsheet *s, int n)
+{
+ struct gnumeric_reader *gr = (struct gnumeric_reader *) s;
+
+ while ((gr->spreadsheet.sheets[n].last_col == -1)
+ &&
+ (1 == xmlTextReaderRead (gr->msd.xtr)))
+ {
+ process_node (gr, &gr->msd);
+ }
+
+ assert (n < gr->n_sheets);
+ return gr->spreadsheet.sheets[n].last_col + 1;
+}
+
+static struct gnumeric_reader *
+gnumeric_reopen (struct gnumeric_reader *r, const char *filename, bool show_errors);
+
+
+static char *
+gnumeric_get_sheet_cell (struct spreadsheet *s, int n, int row, int column)
+{
+ struct gnumeric_reader *gr = (struct gnumeric_reader *) s;
+
+ /* See if this cell is in the cache. If it is, then use it. */
+ if (use_cache)
+ {
+ struct cache_datum *lookup = NULL;
+ unsigned int hash = hash_int (row, 0);
+ hash = hash_int (column, hash);
+
+ HMAP_FOR_EACH_WITH_HASH (lookup, struct cache_datum, node, hash,
+ &gr->cache)
+ {
+ if (lookup->row == row && lookup->col == column)
+ {
+ break;
+ }
+ }
+ if (lookup)
+ {
+ return strdup (lookup->value);
+ }
+ }
+
+ struct state_data sd;
+
+ sd.state = STATE_PRE_INIT;
+ sd.current_sheet = -1;
+ sd.row = -1;
+ sd.col = -1;
+ sd.min_col = 0;
+ sd.gz = gzopen (s->file_name, "r");
+
+ sd.xtr = xmlReaderForIO ((xmlInputReadCallback) gzread,
+ (xmlInputCloseCallback) gzclose,
+ sd.gz,
+ NULL, NULL,
+ 0);
+
+
+ gr->target_sheet_name = NULL;
+
+ int current_row = -1;
+ int current_col = -1;
+
+ /* Spool to the target cell, caching values of cells as they are encountered. */
+ for (int ret = 1; ret; )
+ {
+ while ((ret = xmlTextReaderRead (sd.xtr)))
+ {
+ process_node (gr, &sd);
+ if (sd.state == STATE_CELL)
+ {
+ if (sd.current_sheet == n)
+ {
+ current_row = sd.row;
+ current_col = sd.col;
+ break;
+ }
+ }
+ }
+ if (current_row >= row && current_col >= column - 1)
+ break;
+
+ while ((ret = xmlTextReaderRead (sd.xtr)))
+ {
+ process_node (gr, &sd);
+ if (sd.node_type == XML_READER_TYPE_TEXT)
+ break;
+ }
+
+ if (use_cache)
+ {
+ /* See if this cell has already been cached ... */
+ unsigned int hash = hash_int (current_row, 0);
+ hash = hash_int (current_col, hash);
+ struct cache_datum *probe = NULL;
+ HMAP_FOR_EACH_WITH_HASH (probe, struct cache_datum, node, hash,
+ &gr->cache)
+ {
+ if (probe->row == current_row && probe->col == current_col)
+ break;
+ }
+ /* If not, then cache it. */
+ if (!probe)
+ {
+ char *str = CHAR_CAST (char *, xmlTextReaderValue (sd.xtr));
+ struct cache_datum *cell_data = XMALLOC (struct cache_datum);
+ cell_data->row = current_row;
+ cell_data->col = current_col;
+ cell_data->value = str;
+ hmap_insert (&gr->cache, &cell_data->node, hash);
+ }
+ }
+ }
+
+ while (xmlTextReaderRead (sd.xtr))