Merge branch release-4-6
[alexxy/gromacs.git] / src / external / tng_io / src / lib / tng_io.c
1 /* This code is part of the tng binary trajectory format.
2  *
3  *                      VERSION 1.5
4  *
5  * Written by Magnus Lundborg
6  * Copyright (c) 2012-2013, The GROMACS development team.
7  * Check out http://www.gromacs.org for more information.
8  *
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the Revised BSD License.
12  */
13
14 #ifdef USE_STD_INTTYPES_H
15 #include <inttypes.h>
16 #endif
17
18 #include <limits.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <time.h>
22 #include <math.h>
23 #ifdef USE_ZLIB
24 #include <zlib.h>
25 #endif
26
27 #include "../../include/tng_io.h"
28 #include "../../include/md5.h"
29 #include "../../include/compression/tng_compress.h"
30
31
32 struct tng_bond {
33     /** One of the atoms of the bond */
34     int64_t from_atom_id;
35     /** The other atom of the bond */
36     int64_t to_atom_id;
37 };
38
39 struct tng_atom {
40     /** The residue containing this atom */
41     tng_residue_t residue;
42     /** A unique (per molecule) ID number of the atom */
43     int64_t id;
44     /** The atom_type (depending on the forcefield) */
45     char *atom_type;
46     /** The name of the atom */
47     char *name;
48 };
49
50 struct tng_residue {
51     /** The chain containing this residue */
52     tng_chain_t chain;
53     /** A unique (per chain) ID number of the residue */
54     int64_t id;
55     /** The name of the residue */
56     char *name;
57     /** The number of atoms in the residue */
58     int64_t n_atoms;
59     /** A list of atoms in the residue */
60     int64_t atoms_offset;
61 };
62
63 struct tng_chain {
64     /** The molecule containing this chain */
65     tng_molecule_t molecule;
66     /** A unique (per molecule) ID number of the chain */
67     int64_t id;
68     /** The name of the chain */
69     char *name;
70     /** The number of residues in the chain */
71     int64_t n_residues;
72     /** A list of residues in the chain */
73     tng_residue_t residues;
74 };
75
76 struct tng_molecule {
77     /** A unique ID number of the molecule */
78     int64_t id;
79     /** Quaternary structure of the molecule.
80      *  1 => monomeric
81      *  2 => dimeric
82      *  3 => trimeric
83      *  etc */
84     int64_t quaternary_str;
85     /** The number of chains in the molecule */
86     int64_t n_chains;
87     /** The number of residues in the molecule */
88     int64_t n_residues;
89     /** The number of atoms in the molecule */
90     int64_t n_atoms;
91     /** The number of bonds in the molecule. If the bonds are not specified this
92      * value can be 0. */
93     int64_t n_bonds;
94     /** The name of the molecule */
95     char *name;
96     /** A list of chains in the molecule */
97     tng_chain_t chains;
98     /** A list of residues in the molecule */
99     tng_residue_t residues;
100     /** A list of the atoms in the molecule */
101     tng_atom_t atoms;
102     /** A list of the bonds in the molecule */
103     tng_bond_t bonds;
104 };
105
106 struct tng_gen_block {
107     /** The size of the block header in bytes */
108     int64_t header_contents_size;
109     /** The size of the block contents in bytes */
110     int64_t block_contents_size;
111     /** The ID of the block to determine its type */
112     int64_t id;
113     /** The MD5 hash of the block to verify integrity */
114     char md5_hash[TNG_MD5_HASH_LEN];
115     /** The name of the block */
116     char *name;
117     /** The library version used to write the block */
118     int64_t block_version;
119     int64_t alt_hash_type;
120     int64_t alt_hash_len;
121     char *alt_hash;
122     int64_t signature_type;
123     int64_t signature_len;
124     char *signature;
125     /** The full block header contents */
126     char *header_contents;
127     /** The full block contents */
128     char *block_contents;
129 };
130
131 struct tng_particle_mapping {
132     /** The index number of the first particle in this mapping block */
133     int64_t num_first_particle;
134     /** The number of particles list in this mapping block */
135     int64_t n_particles;
136     /** the mapping of index numbers to the real particle numbers in the
137      * trajectory. real_particle_numbers[0] is the real particle number
138      * (as it is numbered in the molecular system) of the first particle
139      * in the data blocks covered by this particle mapping block */
140     int64_t *real_particle_numbers;
141 };
142
143 struct tng_trajectory_frame_set {
144     /** The number of different particle mapping blocks present. */
145     int64_t n_mapping_blocks;
146     /** The atom mappings of this frame set */
147     struct tng_particle_mapping *mappings;
148     /** The first frame of this frame set */
149     int64_t first_frame;
150     /** The number of frames in this frame set */
151     int64_t n_frames;
152     /** The number of written frames in this frame set (used when writing one
153      * frame at a time). */
154     int64_t n_written_frames;
155     /** The number of frames not yet written to file in this frame set
156      * (used from the utility functions to finish the writing properly. */
157     int64_t n_unwritten_frames;
158
159
160     /** A list of the number of each molecule type - only used when using
161      * variable number of atoms */
162     int64_t *molecule_cnt_list;
163     /** The number of particles/atoms - only used when using variable number
164      * of atoms */
165     int64_t n_particles;
166     /** The file position of the next frame set */
167     int64_t next_frame_set_file_pos;
168     /** The file position of the previous frame set */
169     int64_t prev_frame_set_file_pos;
170     /** The file position of the frame set one long stride step ahead */
171     int64_t medium_stride_next_frame_set_file_pos;
172     /** The file position of the frame set one long stride step behind */
173     int64_t medium_stride_prev_frame_set_file_pos;
174     /** The file position of the frame set one long stride step ahead */
175     int64_t long_stride_next_frame_set_file_pos;
176     /** The file position of the frame set one long stride step behind */
177     int64_t long_stride_prev_frame_set_file_pos;
178     /** Time stamp (in seconds) of first frame in frame set */
179     double first_frame_time;
180
181     /* The data blocks in a frame set are trajectory data blocks */
182     /** The number of trajectory data blocks of particle dependent data */
183     int n_particle_data_blocks;
184     /** A list of data blocks containing particle dependent data */
185     struct tng_particle_data *tr_particle_data;
186     /** The number of trajectory data blocks independent of particles */
187     int n_data_blocks;
188     /** A list of data blocks containing particle indepdendent data */
189     struct tng_non_particle_data *tr_data;
190 };
191
192 /* FIXME: Should there be a pointer to a tng_gen_block from each data block? */
193 struct tng_particle_data {
194     /** The block ID of the data block containing this particle data.
195      *  This is used to determine the kind of data that is stored */
196     int64_t block_id;
197     /** The name of the data block. This is used to determine the kind of
198      *  data that is stored */
199     char *block_name;
200     /** The type of data stored. */
201     char datatype;
202     /** The frame number of the first data value */
203     int64_t first_frame_with_data;
204     /** The number of frames in this frame set */
205     int64_t n_frames;
206     /** The number of values stored per frame */
207     int64_t n_values_per_frame;
208     /** The number of frames between each data point - e.g. when
209      *  storing sparse data. */
210     int64_t stride_length;
211     /** ID of the CODEC used for compression 0 == no compression. */
212     int64_t codec_id;
213     /** If reading one frame at a time this is the last read frame */
214     int64_t last_retrieved_frame;
215     /** The multiplier used for getting integer values for compression */
216     double compression_multiplier;
217     /** A 1-dimensional array of values of length
218      *  [sizeof (datatype)] * n_frames * n_particles * n_values_per_frame */
219     void *values;
220     /** If storing character data store it in a 3-dimensional array */
221     char ****strings;
222 };
223
224 struct tng_non_particle_data {
225     /** The ID of the data block */
226     int64_t block_id;
227     /** The name of the data block. This is used to determine the kind of
228      *  data that is stored */
229     char *block_name;
230     /** The type of data stored. */
231     char datatype;
232     /** The first frame number of the first data value */
233     int64_t first_frame_with_data;
234     /** The number of frames in this data block */
235     int64_t n_frames;
236     /** The number of values stored per frame */
237     int64_t n_values_per_frame;
238     /** The number of frames between each data value, e.g. if storing data
239      *  that is not saved every frame. */
240     int64_t stride_length;
241     /** ID of the CODEC used for compression. 0 == no compression. */
242     int64_t codec_id;
243     /** If reading one frame at a time this is the last read frame */
244     int64_t last_retrieved_frame;
245     /** Compressed data is stored as integers. This compression multiplier is
246      *  the multiplication factor to convert from integer to float/double */
247     double compression_multiplier;
248     /** A 1-dimensional array of values of length
249      *  [sizeof (datatype)] * n_frames * n_values_per_frame */
250     void *values;
251     /** If storing character data store it in a 3-dimensional array */
252     char ***strings;
253 };
254
255
256
257 struct tng_trajectory {
258     /** The path of the input trajectory file */
259     char *input_file_path;
260     /** A handle to the input file */
261     FILE *input_file;
262     /** The length of the input file */
263     long input_file_len;
264     /** The path of the output trajectory file */
265     char *output_file_path;
266     /** A handle to the output file */
267     FILE *output_file;
268     /** Function to swap 32 bit values to and from the endianness of the
269      * input file */
270     tng_function_status (*input_endianness_swap_func_32)(const tng_trajectory_t, int32_t *);
271     /** Function to swap 64 bit values to and from the endianness of the
272      * input file */
273     tng_function_status (*input_endianness_swap_func_64)(const tng_trajectory_t, int64_t *);
274     /** Function to swap 32 bit values to and from the endianness of the
275      * input file */
276     tng_function_status (*output_endianness_swap_func_32)(const tng_trajectory_t, int32_t *);
277     /** Function to swap 64 bit values to and from the endianness of the
278      * input file */
279     tng_function_status (*output_endianness_swap_func_64)(const tng_trajectory_t, int64_t *);
280     /** The endianness of 32 bit values of the current computer */
281     char endianness_32;
282     /** The endianness of 64 bit values of the current computer */
283     char endianness_64;
284
285     /** The name of the program producing this trajectory */
286     char *first_program_name;
287     /** The forcefield used in the simulations */
288     char *forcefield_name;
289     /** The name of the user running the simulations */
290     char *first_user_name;
291     /** The name of the computer on which the simulations were performed */
292     char *first_computer_name;
293     /** The PGP signature of the user creating the file. */
294     char *first_pgp_signature;
295     /** The name of the program used when making last modifications to the
296      *  file */
297     char *last_program_name;
298     /** The name of the user making the last modifications to the file */
299     char *last_user_name;
300     /** The name of the computer on which the last modifications were made */
301     char *last_computer_name;
302     /** The PGP signature of the user making the last modifications to the
303      *  file. */
304     char *last_pgp_signature;
305     /** The time (n seconds since 1970) when the file was created */
306     int64_t time;
307     /** The exponential of the value of the distance unit used. The default
308      * distance unit is nm (1e-9), i.e. distance_unit_exponential = -9. If
309      * the measurements are in Ã… the distance_unit_exponential = -10. */
310     int64_t distance_unit_exponential;
311
312     /** A flag indicating if the number of atoms can vary throughout the
313      *  simulation, e.g. using a grand canonical ensemble */
314     char var_num_atoms_flag;
315     /** The number of frames in a frame set. It is allowed to have frame sets
316      *  with fewer frames, but this will help searching for specific frames */
317     int64_t frame_set_n_frames;
318     /** The number of frame sets in a medium stride step */
319     int64_t medium_stride_length;
320     /** The number of frame sets in a long stride step */
321     int64_t long_stride_length;
322     /** The current (can change from one frame set to another) time length
323      *  (in seconds) of one frame */
324     double time_per_frame;
325
326     /** The number of different kinds of molecules in the trajectory */
327     int64_t n_molecules;
328     /** A list of molecules in the trajectory */
329     tng_molecule_t molecules;
330     /** A list of the count of each molecule - if using variable number of
331      *  particles this will be specified in each frame set */
332     int64_t *molecule_cnt_list;
333     /** The total number of particles/atoms. If using variable number of
334      *  particles this will be specified in each frame set */
335     int64_t n_particles;
336
337      /** The pos in the src file of the first frame set */
338     int64_t first_trajectory_frame_set_input_file_pos;
339     /** The pos in the dest file of the first frame set */
340     int64_t first_trajectory_frame_set_output_file_pos;
341     /** The pos in the src file of the last frame set */
342     int64_t last_trajectory_frame_set_input_file_pos;
343     /** The pos in the dest file of the last frame set */
344     int64_t last_trajectory_frame_set_output_file_pos;
345     /** The currently active frame set */
346     struct tng_trajectory_frame_set current_trajectory_frame_set;
347     /** The pos in the src file of the current frame set */
348     long current_trajectory_frame_set_input_file_pos;
349     /** The pos in the dest file of the current frame set */
350     long current_trajectory_frame_set_output_file_pos;
351     /** The number of frame sets in the trajectory N.B. Not saved in file and
352      *  cannot be trusted to be up-to-date */
353     int64_t n_trajectory_frame_sets;
354
355     /** The number of trajectory blocks in the file */
356     int64_t n_trajectory_blocks;
357
358     /* These data blocks are non-trajectory data blocks */
359     /** The number of non-frame dependent particle dependent data blocks */
360     int n_particle_data_blocks;
361     /** A list of data blocks containing particle dependent data */
362     struct tng_particle_data *non_tr_particle_data;
363
364     /** The number of frame and particle independent data blocks */
365     int n_data_blocks;
366     /** A list of frame and particle indepdendent data blocks */
367     struct tng_non_particle_data *non_tr_data;
368
369     /** TNG compression algorithm for compressing positions */
370     int *compress_algo_pos;
371     /** TNG compression algorithm for compressing velocities */
372     int *compress_algo_vel;
373     /** The precision used for lossy compression */
374     double compression_precision;
375 };
376
377 #ifndef USE_WINDOWS
378 #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
379 #define USE_WINDOWS
380 #endif /* win32... */
381 #endif /* not defined USE_WINDOWS */
382
383 #ifdef USE_WINDOWS
384 #define TNG_INLINE __inline
385 #define TNG_SNPRINTF _snprintf
386 #else
387 #define TNG_INLINE inline
388 #define TNG_SNPRINTF snprintf
389 #endif
390
391 static TNG_INLINE int tng_min_i(int a, int b)
392 {
393     return (a < b ? a : b);
394 }
395
396 /*
397 static TNG_INLINE int tng_max_i(int a, int b)
398 {
399     return (a > b ? a : b);
400 }
401 */
402 static TNG_INLINE int64_t tng_min_i64(int64_t a, int64_t b)
403 {
404     return (a < b ? a : b);
405 }
406
407 static TNG_INLINE int64_t tng_max_i64(int64_t a, int64_t b)
408 {
409     return (a > b ? a : b);
410 }
411
412 /*
413 static TNG_INLINE float tng_min_f(float a, float b)
414 {
415     return (a < b ? a : b);
416 }
417
418 static TNG_INLINE float tng_max_f(float a, float b)
419 {
420     return (a > b ? a : b);
421 }
422
423 static TNG_INLINE double tng_min_d(double a, double b)
424 {
425     return (a < b ? a : b);
426 }
427
428 static TNG_INLINE double tng_max_d(double a, double b)
429 {
430     return (a > b ? a : b);
431 }
432 */
433
434 /** This function swaps the byte order of a 32 bit numerical variable
435  * to big endian.
436  * It does not only work with integer, but e.g. floats need casting.
437  * If the byte order is already big endian no change is needed.
438  * @param tng_data is a trajectory data container.
439  * @param v is a pointer to a 32 bit numerical value (float or integer).
440  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
441  * byte order is not recognised.
442  */
443 static tng_function_status tng_swap_byte_order_big_endian_32
444                 (const tng_trajectory_t tng_data, int32_t *v)
445 {
446     switch(tng_data->endianness_32)
447     {
448     case TNG_LITTLE_ENDIAN_32: /* Byte order is reversed. */
449         *v = ((*v & 0xFF000000) >> 24) | /* Move first byte to end */
450              ((*v & 0x00FF0000) >> 8) |  /* Move 2nd byte to pos 3 */
451              ((*v & 0x0000FF00) << 8) |  /* Move 3rd byte to pos 2 */
452              ((*v & 0x000000FF) << 24);  /* Move last byte to first */
453
454         return(TNG_SUCCESS);
455
456     case TNG_BYTE_PAIR_SWAP_32: /* byte pair swap */
457         *v = ((*v & 0xFFFF0000) >> 16) |
458              ((*v & 0x0000FFFF) << 16);
459
460         return(TNG_SUCCESS);
461
462     case TNG_BIG_ENDIAN_32: /* Already correct */
463         return(TNG_SUCCESS);
464
465     default:
466         return(TNG_FAILURE);
467     }
468 }
469
470 /** This function swaps the byte order of a 64 bit numerical variable
471  * to big endian.
472  * It does not only work with integer, but e.g. floats need casting.
473  * The byte order swapping routine can convert four different byte
474  * orders to big endian.
475  * If the byte order is already big endian no change is needed.
476  * @param tng_data is a trajectory data container.
477  * @param v is a pointer to a 64 bit numerical value (double or integer).
478  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
479  * byte order is not recognised.
480  */
481 static tng_function_status tng_swap_byte_order_big_endian_64
482                 (const tng_trajectory_t tng_data, int64_t *v)
483 {
484     switch(tng_data->endianness_64)
485     {
486     case TNG_LITTLE_ENDIAN_64: /* Byte order is reversed. */
487         *v = ((*v & 0xFF00000000000000LL) >> 56) | /* Move first byte to end */
488              ((*v & 0x00FF000000000000LL) >> 40) | /* Move 2nd byte to pos 7 */
489              ((*v & 0x0000FF0000000000LL) >> 24) | /* Move 3rd byte to pos 6 */
490              ((*v & 0x000000FF00000000LL) >> 8 ) | /* Move 4th byte to pos 5 */
491              ((*v & 0x00000000FF000000LL) << 8 ) | /* Move 5th byte to pos 4 */
492              ((*v & 0x0000000000FF0000LL) << 24) | /* Move 6th byte to pos 3 */
493              ((*v & 0x000000000000FF00LL) << 40) | /* Move 7th byte to pos 2 */
494              ((*v & 0x00000000000000FFLL) << 56);  /* Move last byte to first */
495
496         return(TNG_SUCCESS);
497
498     case TNG_QUAD_SWAP_64: /* Byte quad swap */
499         *v = ((*v & 0xFFFFFFFF00000000LL) >> 32) |
500              ((*v & 0x00000000FFFFFFFFLL) << 32);
501
502         return(TNG_SUCCESS);
503
504     case TNG_BYTE_PAIR_SWAP_64: /* Byte pair swap */
505         *v = ((*v & 0xFFFF0000FFFF0000LL) >> 16) |
506              ((*v & 0x0000FFFF0000FFFFLL) << 16);
507
508         return(TNG_SUCCESS);
509
510     case TNG_BYTE_SWAP_64: /* Byte swap */
511         *v = ((*v & 0xFF00FF00FF00FF00LL) >> 8) |
512              ((*v & 0x00FF00FF00FF00FFLL) << 8);
513
514         return(TNG_SUCCESS);
515
516     case TNG_BIG_ENDIAN_64: /* Already correct */
517         return(TNG_SUCCESS);
518
519     default:
520         return(TNG_FAILURE);
521     }
522 }
523
524 /** This function swaps the byte order of a 32 bit numerical variable
525  * to little endian.
526  * It does not only work with integer, but e.g. floats need casting.
527  * If the byte order is already little endian no change is needed.
528  * @param tng_data is a trajectory data container.
529  * @param v is a pointer to a 32 bit numerical value (float or integer).
530  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
531  * byte order is not recognised.
532  */
533 static tng_function_status tng_swap_byte_order_little_endian_32
534                 (const tng_trajectory_t tng_data, int32_t *v)
535 {
536     switch(tng_data->endianness_32)
537     {
538     case TNG_LITTLE_ENDIAN_32: /* Already correct */
539         return(TNG_SUCCESS);
540
541     case TNG_BYTE_PAIR_SWAP_32: /* byte pair swapped big endian to little endian */
542         *v = ((*v & 0xFF00FF00) >> 8) |
543              ((*v & 0x00FF00FF) << 8);
544
545         return(TNG_SUCCESS);
546
547     case TNG_BIG_ENDIAN_32: /* Byte order is reversed. */
548         *v = ((*v & 0xFF000000) >> 24) | /* Move first byte to end */
549              ((*v & 0x00FF0000) >> 8) |  /* Move 2nd byte to pos 3 */
550              ((*v & 0x0000FF00) << 8) |  /* Move 3rd byte to pos 2 */
551              ((*v & 0x000000FF) << 24);  /* Move last byte to first */
552
553         return(TNG_SUCCESS);
554
555     default:
556         return(TNG_FAILURE);
557     }
558 }
559
560 /** This function swaps the byte order of a 64 bit numerical variable
561  * to little endian.
562  * It does not only work with integer, but e.g. floats need casting.
563  * The byte order swapping routine can convert four different byte
564  * orders to little endian.
565  * If the byte order is already little endian no change is needed.
566  * @param tng_data is a trajectory data container.
567  * @param v is a pointer to a 64 bit numerical value (double or integer).
568  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
569  * byte order is not recognised.
570  */
571 static tng_function_status tng_swap_byte_order_little_endian_64
572                 (const tng_trajectory_t tng_data, int64_t *v)
573 {
574     switch(tng_data->endianness_64)
575     {
576     case TNG_LITTLE_ENDIAN_64: /* Already correct */
577         return(TNG_SUCCESS);
578
579     case TNG_QUAD_SWAP_64: /* Byte quad swapped big endian to little endian */
580         *v = ((*v & 0xFF000000FF000000LL) >> 24) |
581              ((*v & 0x00FF000000FF0000LL) >> 8) |
582              ((*v & 0x0000FF000000FF00LL) << 8) |
583              ((*v & 0x000000FF000000FFLL) << 24);
584
585         return(TNG_SUCCESS);
586
587     case TNG_BYTE_PAIR_SWAP_64: /* Byte pair swapped big endian to little endian */
588         *v = ((*v & 0xFF00FF0000000000LL) >> 40) |
589              ((*v & 0x00FF00FF00000000LL) >> 24) |
590              ((*v & 0x00000000FF00FF00LL) << 24) |
591              ((*v & 0x0000000000FF00FFLL) << 40);
592
593         return(TNG_SUCCESS);
594
595     case TNG_BYTE_SWAP_64: /* Byte swapped big endian to little endian */
596         *v = ((*v & 0xFFFF000000000000LL) >> 48) |
597              ((*v & 0x0000FFFF00000000LL) >> 16) |
598              ((*v & 0x00000000FFFF0000LL) << 16) |
599              ((*v & 0x000000000000FFFFLL) << 48);
600
601         return(TNG_SUCCESS);
602
603     case TNG_BIG_ENDIAN_64: /* Byte order is reversed. */
604         *v = ((*v & 0xFF00000000000000LL) >> 56) | /* Move first byte to end */
605              ((*v & 0x00FF000000000000LL) >> 40) | /* Move 2nd byte to pos 7 */
606              ((*v & 0x0000FF0000000000LL) >> 24) | /* Move 3rd byte to pos 6 */
607              ((*v & 0x000000FF00000000LL) >> 8 ) | /* Move 4th byte to pos 5 */
608              ((*v & 0x00000000FF000000LL) << 8 ) | /* Move 5th byte to pos 4 */
609              ((*v & 0x0000000000FF0000LL) << 24) | /* Move 6th byte to pos 3 */
610              ((*v & 0x000000000000FF00LL) << 40) | /* Move 7th byte to pos 2 */
611              ((*v & 0x00000000000000FFLL) << 56);  /* Move last byte to first */
612
613         return(TNG_SUCCESS);
614
615     default:
616         return(TNG_FAILURE);
617     }
618 }
619 /** Generate the md5 hash of a block.
620  * The hash is created based on the actual block contents.
621  * @param block is a general block container.
622  * @return TNG_SUCCESS (0) if successful.
623  */
624 static tng_function_status tng_block_md5_hash_generate(tng_gen_block_t block)
625 {
626     md5_state_t md5_state;
627
628     md5_init(&md5_state);
629     md5_append(&md5_state, (md5_byte_t *)block->block_contents,
630                (int)block->block_contents_size);
631     md5_finish(&md5_state, (md5_byte_t *)block->md5_hash);
632
633     return(TNG_SUCCESS);
634 }
635
636 /** Compare the current block md5 hash (e.g. read from file) with the md5 hash
637  * calculated from the current contents.
638  * If the current md5 hash is not set skip the comparison.
639  * @param block is a general block container.
640  * @param results If the hashes match results is set to TNG_TRUE, otherwise it is
641  * set to TNG_FALSE. If the hash was not set results is set to TNG_TRUE.
642  * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the hash was not
643  * set.
644  */
645 static tng_function_status tng_md5_hash_match_verify(tng_gen_block_t block,
646                                                      tng_bool *results)
647 {
648     md5_state_t md5_state;
649     char hash[TNG_MD5_HASH_LEN];
650
651     TNG_ASSERT(block->block_contents_size > 0, "The block contents size must be > 0");
652
653     *results = TNG_TRUE;
654     if(strncmp(block->md5_hash, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0)
655     {
656         return(TNG_FAILURE);
657     }
658     md5_init(&md5_state);
659     md5_append(&md5_state, (md5_byte_t *)block->block_contents,
660                (int)block->block_contents_size);
661     md5_finish(&md5_state, (md5_byte_t *)hash);
662
663     if(strncmp(block->md5_hash, hash, 16) != 0)
664     {
665         *results = TNG_FALSE;
666     }
667
668     return(TNG_SUCCESS);
669 }
670
671 /** Open the input file if it is not already opened.
672  * @param tng_data is a trajectory data container.
673  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
674  * error has occured.
675  */
676 static tng_function_status tng_input_file_init(tng_trajectory_t tng_data)
677 {
678     if(!tng_data->input_file)
679     {
680         if(!tng_data->input_file_path)
681         {
682             fprintf(stderr, "TNG library: No file specified for reading. %s: %d\n",
683                    __FILE__, __LINE__);
684             return(TNG_CRITICAL);
685         }
686         tng_data->input_file = fopen(tng_data->input_file_path, "rb");
687         if(!tng_data->input_file)
688         {
689             fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
690                    tng_data->input_file_path, __FILE__, __LINE__);
691             return(TNG_CRITICAL);
692         }
693     }
694     return(TNG_SUCCESS);
695 }
696
697 /** Open the output file if it is not already opened
698  * @param tng_data is a trajectory data container.
699  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
700  * error has occured.
701  */
702 static tng_function_status tng_output_file_init(tng_trajectory_t tng_data)
703 {
704     if(!tng_data->output_file)
705     {
706         if(!tng_data->output_file_path)
707         {
708             fprintf(stderr, "TNG library: No file specified for writing. %s: %d\n",
709                    __FILE__, __LINE__);
710             return(TNG_CRITICAL);
711         }
712
713         tng_data->output_file = fopen(tng_data->output_file_path, "wb+");
714
715         if(!tng_data->output_file)
716         {
717             fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
718                    tng_data->output_file_path, __FILE__, __LINE__);
719             return(TNG_CRITICAL);
720         }
721     }
722     return(TNG_SUCCESS);
723 }
724
725 /** Setup a file block container.
726  * @param block_p a pointer to memory to initialise as a file block container.
727  * @details Memory is allocated during initialisation.
728  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
729  * error has occured.
730  */
731 static tng_function_status tng_block_init(struct tng_gen_block **block_p)
732 {
733     tng_gen_block_t block;
734
735     *block_p = malloc(sizeof(struct tng_gen_block));
736     if(!*block_p)
737     {
738         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
739                sizeof(struct tng_gen_block), __FILE__, __LINE__);
740         return(TNG_CRITICAL);
741     }
742
743     block = *block_p;
744
745     block->id = -1;
746     /* Reset the md5_hash */
747     memcpy(block->md5_hash, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", TNG_MD5_HASH_LEN);
748     block->name = 0;
749     block->block_version = TNG_VERSION;
750     block->header_contents = 0;
751     block->header_contents_size = 0;
752     block->block_contents = 0;
753     block->block_contents_size = 0;
754
755     return(TNG_SUCCESS);
756 }
757
758 /**
759  * @brief Clean up a file block container.
760  * @param block_p a pointer to the file block container to destroy.
761  * @details All allocated memory in the data structure is freed, as well as
762  * block_p itself.
763  * @return TNG_SUCCESS (0) if successful.
764  */
765 static tng_function_status tng_block_destroy(struct tng_gen_block **block_p)
766 {
767     tng_gen_block_t block = *block_p;
768
769     if(!*block_p)
770     {
771         return(TNG_SUCCESS);
772     }
773
774 /*     fprintf(stderr, "TNG library: Destroying block\n"); */
775     if(block->name)
776     {
777         free(block->name);
778         block->name = 0;
779     }
780     if(block->header_contents)
781     {
782         free(block->header_contents);
783         block->header_contents = 0;
784     }
785     if(block->block_contents)
786     {
787         free(block->block_contents);
788         block->block_contents = 0;
789     }
790
791     free(*block_p);
792     *block_p = 0;
793
794     return(TNG_SUCCESS);
795 }
796
797 /** Read the header of a data block, regardless of its type
798  * @param tng_data is a trajectory data container.
799  * @param block is a general block container.
800  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
801  * error has occured.
802  */
803 static tng_function_status tng_block_header_read
804                 (tng_trajectory_t tng_data, tng_gen_block_t block)
805 {
806     int len, offset = 0;
807
808     TNG_ASSERT(block != 0, "TNG library: Trying to read to uninitialized block (NULL pointer).");
809
810     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
811     {
812         return(TNG_CRITICAL);
813     }
814
815     /* First read the header size to be able to read the whole header. */
816     if(fread(&block->header_contents_size, sizeof(block->header_contents_size),
817         1, tng_data->input_file) == 0)
818     {
819         fprintf(stderr, "TNG library: Cannot read header size. %s: %d\n",
820                __FILE__, __LINE__);
821         return(TNG_CRITICAL);
822     }
823
824     /* If this was the size of the general info block check the endianness */
825     if(ftell(tng_data->input_file) < 9)
826     {
827         /* File is little endian */
828         if ( *((const char*)&block->header_contents_size) != 0x00 &&
829              *((const char*)(&block->header_contents_size) + 7) == 0x00)
830         {
831             /* If the architecture endianness is little endian no byte swap
832              * will be needed. Otherwise use the functions to swap to little
833              * endian */
834             if(tng_data->endianness_32 == TNG_LITTLE_ENDIAN_32)
835             {
836                 tng_data->input_endianness_swap_func_32 = 0;
837             }
838             else
839             {
840                 tng_data->input_endianness_swap_func_32 =
841                 &tng_swap_byte_order_little_endian_32;
842             }
843             if(tng_data->endianness_64 == TNG_LITTLE_ENDIAN_64)
844             {
845                 tng_data->input_endianness_swap_func_64 = 0;
846             }
847             else
848             {
849                 tng_data->input_endianness_swap_func_64 =
850                 &tng_swap_byte_order_little_endian_64;
851             }
852         }
853         /* File is big endian */
854         else
855         {
856             /* If the architecture endianness is big endian no byte swap
857              * will be needed. Otherwise use the functions to swap to big
858              * endian */
859             if(tng_data->endianness_32 == TNG_BIG_ENDIAN_32)
860             {
861                 tng_data->input_endianness_swap_func_32 = 0;
862             }
863             else
864             {
865                 tng_data->input_endianness_swap_func_32 =
866                 &tng_swap_byte_order_big_endian_32;
867             }
868             if(tng_data->endianness_64 == TNG_BIG_ENDIAN_64)
869             {
870                 tng_data->input_endianness_swap_func_64 = 0;
871             }
872             else
873             {
874                 tng_data->input_endianness_swap_func_64 =
875                 &tng_swap_byte_order_big_endian_64;
876             }
877         }
878     }
879
880     if(tng_data->input_endianness_swap_func_64)
881     {
882         if(tng_data->input_endianness_swap_func_64(tng_data,
883                                                    &block->header_contents_size)
884             != TNG_SUCCESS)
885         {
886             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
887                     __FILE__, __LINE__);
888         }
889     }
890
891     /* Move the reading position to the beginning of the header. */
892     fseek(tng_data->input_file, -(long)sizeof(block->header_contents_size),
893           SEEK_CUR);
894
895     /* If there is already memory allocated for the contents free it (we do not
896      * know if the size is correct). */
897     if(block->header_contents)
898     {
899         free(block->header_contents);
900     }
901
902     block->header_contents = malloc(block->header_contents_size);
903     if(!block->header_contents)
904     {
905         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
906                block->header_contents_size, __FILE__, __LINE__);
907         return(TNG_CRITICAL);
908     }
909
910     /* Read the whole header into header_contents. This way it can be saved
911      * even if it cannot be interpreted
912      * for one reason or another. */
913     if(fread(block->header_contents, block->header_contents_size, 1,
914         tng_data->input_file) == 0)
915     {
916         fprintf(stderr, "TNG library: Cannot read header. %s: %d\n", __FILE__, __LINE__);
917         return(TNG_CRITICAL);
918     }
919
920     /* The header contents size has already been read. Skip ahead. */
921     offset = sizeof(block->header_contents_size);
922
923
924     /* Copy the respective parameters from the header contents block */
925     memcpy(&block->block_contents_size, block->header_contents+offset,
926            sizeof(block->block_contents_size));
927     if(tng_data->input_endianness_swap_func_64)
928     {
929         if(tng_data->input_endianness_swap_func_64(tng_data,
930                                                    &block->block_contents_size)
931             != TNG_SUCCESS)
932         {
933             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
934                     __FILE__, __LINE__);
935         }
936     }
937
938     offset += sizeof(block->block_contents_size);
939
940     memcpy(&block->id, block->header_contents+offset, sizeof(block->id));
941     if(tng_data->input_endianness_swap_func_64)
942     {
943         if(tng_data->input_endianness_swap_func_64(tng_data,
944                                                    &block->id)
945             != TNG_SUCCESS)
946         {
947             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
948                     __FILE__, __LINE__);
949         }
950     }
951
952     offset += sizeof(block->id);
953
954     memcpy(block->md5_hash, block->header_contents+offset, TNG_MD5_HASH_LEN);
955     offset += TNG_MD5_HASH_LEN;
956
957     if(block->name && strcmp(block->name, block->header_contents+offset) != 0)
958     {
959         free(block->name);
960         block->name = 0;
961     }
962     len = tng_min_i((int)strlen(block->header_contents+offset) + 1, TNG_MAX_STR_LEN);
963     if(!block->name)
964     {
965         block->name = malloc(len);
966         if(!block->name)
967         {
968             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
969                     __FILE__, __LINE__);
970             return(TNG_CRITICAL);
971         }
972         strncpy(block->name, block->header_contents+offset, len);
973     }
974     offset += len;
975
976     memcpy(&block->block_version, block->header_contents+offset,
977            sizeof(block->block_version));
978     if(tng_data->input_endianness_swap_func_64)
979     {
980         if(tng_data->input_endianness_swap_func_64(tng_data,
981                                                    &block->block_version)
982             != TNG_SUCCESS)
983         {
984             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
985                     __FILE__, __LINE__);
986         }
987     }
988
989     return(TNG_SUCCESS);
990 }
991
992 /** Write a whole block, both header and contents, regardless of it type
993  * @param tng_data is a trajectory data container.
994  * @param block is a general block container.
995  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
996  * has occurred or TNG_CRITICAL (2) if a major error has occured.
997  */
998 /* Disabled until it is used.*/
999 /*
1000 // static tng_function_status tng_block_verbatim_write(tng_trajectory_t tng_data,
1001 //                                                     tng_gen_block_t block)
1002 // {
1003 //     if(!block->header_contents)
1004 //     {
1005 //         fprintf(stderr, "TNG library: No contents to write. %s: %d\n", __FILE__, __LINE__);
1006 //         return(TNG_FAILURE);
1007 //     }
1008 //     if(fwrite(block->header_contents, block->header_contents_size, 1,
1009 //                 tng_data->output_file) != 1)
1010 //     {
1011 //         fprintf(stderr, "TNG library: Could not write all header data. %s: %d\n",
1012 //                 __FILE__, __LINE__);
1013 //         return(TNG_CRITICAL);
1014 //     }
1015 //
1016 //     if(!block->block_contents)
1017 //     {
1018 //         fprintf(stderr, "TNG library: No block data to write. %s: %d\n",
1019 //                 __FILE__, __LINE__);
1020 //         return(TNG_FAILURE);
1021 //     }
1022 //     if(fwrite(block->block_contents, block->block_contents_size, 1,
1023 //                 tng_data->output_file) != 1)
1024 //     {
1025 //         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n",
1026 //                 __FILE__, __LINE__);
1027 //         return(TNG_CRITICAL);
1028 //     }
1029 //     return(TNG_SUCCESS);
1030 // }
1031 */
1032 /** Write the header of a data block, regardless of its type
1033  * @param tng_data is a trajectory data container.
1034  * @param block is a general block container.
1035  * @param hash_mode is an option to decide whether to use the md5 hash or not.
1036  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
1037  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1038  * error has occured.
1039  */
1040 static tng_function_status tng_block_header_write
1041                 (tng_trajectory_t tng_data,
1042                  tng_gen_block_t block,
1043                  const char hash_mode)
1044 {
1045     int name_len, offset = 0;
1046
1047     TNG_ASSERT(block != 0, "TNG library: Trying to write uninitialized block (NULL pointer).");
1048
1049     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
1050     {
1051         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
1052                __FILE__, __LINE__);
1053         return(TNG_CRITICAL);
1054     }
1055
1056     if(!block->name)
1057     {
1058         block->name = malloc(1);
1059         if(!block->name)
1060         {
1061             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1062                    __FILE__, __LINE__);
1063             return(TNG_CRITICAL);
1064         }
1065         block->name[0] = 0;
1066     }
1067
1068     name_len = tng_min_i((int)strlen(block->name) + 1, TNG_MAX_STR_LEN);
1069
1070     if(hash_mode == TNG_USE_HASH)
1071     {
1072         tng_block_md5_hash_generate(block);
1073     }
1074
1075     /* Calculate the size of the header to write */
1076     block->header_contents_size = sizeof(block->header_contents_size) +
1077                                   sizeof(block->block_contents_size) +
1078                                   sizeof(block->id) +
1079                                   sizeof(block->block_version) +
1080                                   TNG_MD5_HASH_LEN +
1081                                   name_len;
1082
1083     if(block->header_contents)
1084     {
1085         free(block->header_contents);
1086     }
1087
1088     block->header_contents = malloc(block->header_contents_size);
1089     if(!block->header_contents)
1090     {
1091         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
1092                block->header_contents_size, __FILE__, __LINE__);
1093         return(TNG_CRITICAL);
1094     }
1095
1096     /* First copy all data into the header_contents block and finally write
1097      * the whole block at once. */
1098     memcpy(block->header_contents, &block->header_contents_size,
1099            sizeof(block->header_contents_size));
1100     if(tng_data->output_endianness_swap_func_64)
1101     {
1102         if(tng_data->output_endianness_swap_func_64(tng_data,
1103                                       (int64_t *)block->header_contents+offset)
1104             != TNG_SUCCESS)
1105         {
1106             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1107                     __FILE__, __LINE__);
1108         }
1109     }
1110     offset += sizeof(block->header_contents_size);
1111
1112     memcpy(block->header_contents+offset, &block->block_contents_size,
1113            sizeof(block->block_contents_size));
1114     if(tng_data->output_endianness_swap_func_64)
1115     {
1116         if(tng_data->output_endianness_swap_func_64(tng_data,
1117                                       (int64_t *)block->header_contents+offset)
1118             != TNG_SUCCESS)
1119         {
1120             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1121                     __FILE__, __LINE__);
1122         }
1123     }
1124     offset += sizeof(block->block_contents_size);
1125
1126     memcpy(block->header_contents+offset, &block->id, sizeof(block->id));
1127     if(tng_data->output_endianness_swap_func_64)
1128     {
1129         if(tng_data->output_endianness_swap_func_64(tng_data,
1130                                       (int64_t *)block->header_contents+offset)
1131             != TNG_SUCCESS)
1132         {
1133             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1134                     __FILE__, __LINE__);
1135         }
1136     }
1137     offset += sizeof(block->id);
1138
1139     memcpy(block->header_contents+offset, block->md5_hash, TNG_MD5_HASH_LEN);
1140     offset += TNG_MD5_HASH_LEN;
1141
1142     strncpy(block->header_contents+offset, block->name, name_len);
1143     offset += name_len;
1144
1145     memcpy(block->header_contents+offset, &block->block_version,
1146            sizeof(block->block_version));
1147     if(tng_data->output_endianness_swap_func_64)
1148     {
1149         if(tng_data->output_endianness_swap_func_64(tng_data,
1150                                       (int64_t *)block->header_contents+offset)
1151             != TNG_SUCCESS)
1152         {
1153             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1154                     __FILE__, __LINE__);
1155         }
1156     }
1157
1158     if(fwrite(block->header_contents, block->header_contents_size,
1159        1, tng_data->output_file) != 1)
1160     {
1161         fprintf(stderr, "TNG library: Could not write all header data. %s: %d\n", __FILE__, __LINE__);
1162         return(TNG_CRITICAL);
1163     }
1164     return(TNG_SUCCESS);
1165 }
1166
1167 /** Read a general info block. This is the first block of a TNG file.
1168  *  Populate the fields in tng_data.
1169  * @param tng_data is a trajectory data container.
1170  * @param block is a general block container.
1171  * @param hash_mode is an option to decide whether to use the md5 hash or not.
1172  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
1173  * compared to the md5 hash of the read contents to ensure valid data.
1174  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1175  * error has occured.
1176  */
1177 static tng_function_status tng_general_info_block_read
1178                 (tng_trajectory_t tng_data, tng_gen_block_t block,
1179                  const char hash_mode)
1180 {
1181     int len, offset = 0;
1182     tng_bool same_hash;
1183
1184     void *temp;
1185
1186     TNG_ASSERT(block != 0, "TNG library: Trying to read data to an uninitialized block (NULL pointer)");
1187
1188     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
1189     {
1190         return(TNG_CRITICAL);
1191     }
1192
1193     temp = realloc(block->block_contents, block->block_contents_size);
1194     if(!temp)
1195     {
1196         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
1197                block->block_contents_size, __FILE__, __LINE__);
1198         free(block->block_contents);
1199         block->block_contents = 0;
1200         return(TNG_CRITICAL);
1201     }
1202     block->block_contents = temp;
1203
1204     /* Read the whole block into block_contents to be able to write it to disk
1205      * even if it cannot be interpreted. */
1206     if(fread(block->block_contents, block->block_contents_size, 1,
1207              tng_data->input_file) == 0)
1208     {
1209         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
1210         return(TNG_CRITICAL);
1211     }
1212
1213     /* FIXME: Does not check if the size of the contents matches the expected
1214      * size or if the contents can be read. */
1215
1216     if(hash_mode == TNG_USE_HASH)
1217     {
1218         tng_md5_hash_match_verify(block, &same_hash);
1219         if(same_hash != TNG_TRUE)
1220         {
1221             fprintf(stderr, "TNG library: General info block contents corrupt. Hashes do not match. "
1222                 "%s: %d\n",
1223                 __FILE__, __LINE__);
1224     /*         return(TNG_FAILURE); */
1225         }
1226     }
1227
1228     len = tng_min_i((int)strlen(block->block_contents) + 1, TNG_MAX_STR_LEN);
1229     temp = realloc(tng_data->first_program_name, len);
1230     if(!temp)
1231     {
1232         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
1233                __FILE__, __LINE__);
1234         free(tng_data->first_program_name);
1235         tng_data->first_program_name = 0;
1236         return(TNG_CRITICAL);
1237     }
1238     tng_data->first_program_name = temp;
1239     strncpy(tng_data->first_program_name, block->block_contents, len);
1240     offset += len;
1241
1242     len = tng_min_i((int)strlen(block->block_contents + offset) + 1, TNG_MAX_STR_LEN);
1243     temp = realloc(tng_data->last_program_name, len);
1244     if(!temp)
1245     {
1246         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
1247                __FILE__, __LINE__);
1248         free(tng_data->last_program_name);
1249         tng_data->last_program_name = 0;
1250         return(TNG_CRITICAL);
1251     }
1252     tng_data->last_program_name = temp;
1253     strncpy(tng_data->last_program_name, block->block_contents + offset, len);
1254     offset += len;
1255
1256     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
1257     temp = realloc(tng_data->first_user_name, len);
1258     if(!temp)
1259     {
1260         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
1261                __FILE__, __LINE__);
1262         free(tng_data->first_user_name);
1263         tng_data->first_user_name = 0;
1264         return(TNG_CRITICAL);
1265     }
1266     tng_data->first_user_name = temp;
1267     strncpy(tng_data->first_user_name, block->block_contents+offset, len);
1268     offset += len;
1269
1270     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
1271     temp = realloc(tng_data->last_user_name, len);
1272     if(!temp)
1273     {
1274         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
1275                __FILE__, __LINE__);
1276         free(tng_data->last_user_name);
1277         tng_data->last_user_name = 0;
1278         return(TNG_CRITICAL);
1279     }
1280     tng_data->last_user_name = temp;
1281     strncpy(tng_data->last_user_name, block->block_contents+offset, len);
1282     offset += len;
1283
1284     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
1285     temp = realloc(tng_data->first_computer_name, len);
1286     if(!temp)
1287     {
1288         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
1289                __FILE__, __LINE__);
1290         free(tng_data->first_computer_name);
1291         tng_data->first_computer_name = 0;
1292         return(TNG_CRITICAL);
1293     }
1294     tng_data->first_computer_name = temp;
1295     strncpy(tng_data->first_computer_name, block->block_contents+offset, len);
1296     offset += len;
1297
1298     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
1299     temp = realloc(tng_data->last_computer_name, len);
1300     if(!temp)
1301     {
1302         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
1303                __FILE__, __LINE__);
1304         free(tng_data->last_computer_name);
1305         tng_data->last_computer_name = 0;
1306         return(TNG_CRITICAL);
1307     }
1308     tng_data->last_computer_name = temp;
1309     strncpy(tng_data->last_computer_name, block->block_contents+offset, len);
1310     offset += len;
1311
1312     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
1313     temp = realloc(tng_data->first_pgp_signature, len);
1314     if(!temp)
1315     {
1316         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
1317                __FILE__, __LINE__);
1318         free(tng_data->first_pgp_signature);
1319         tng_data->first_pgp_signature = 0;
1320         return(TNG_CRITICAL);
1321     }
1322     tng_data->first_pgp_signature = temp;
1323     strncpy(tng_data->first_pgp_signature, block->block_contents+offset, len);
1324     offset += len;
1325
1326     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
1327     temp = realloc(tng_data->last_pgp_signature, len);
1328     if(!temp)
1329     {
1330         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
1331                __FILE__, __LINE__);
1332         free(tng_data->last_pgp_signature);
1333         tng_data->last_pgp_signature = 0;
1334         return(TNG_CRITICAL);
1335     }
1336     tng_data->last_pgp_signature = temp;
1337     strncpy(tng_data->last_pgp_signature, block->block_contents+offset, len);
1338     offset += len;
1339
1340     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
1341     temp = realloc(tng_data->forcefield_name, len);
1342     if(!temp)
1343     {
1344         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
1345                __FILE__, __LINE__);
1346         free(tng_data->forcefield_name);
1347         tng_data->forcefield_name = 0;
1348         return(TNG_CRITICAL);
1349     }
1350     tng_data->forcefield_name = temp;
1351     strncpy(tng_data->forcefield_name, block->block_contents+offset, len);
1352     offset += len;
1353
1354     memcpy(&tng_data->time, block->block_contents+offset,
1355            sizeof(tng_data->time));
1356     if(tng_data->input_endianness_swap_func_64)
1357     {
1358         if(tng_data->input_endianness_swap_func_64(tng_data,
1359                                                    &tng_data->time)
1360             != TNG_SUCCESS)
1361         {
1362             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1363                     __FILE__, __LINE__);
1364         }
1365     }
1366     offset += sizeof(tng_data->time);
1367
1368     memcpy(&tng_data->var_num_atoms_flag, block->block_contents+offset,
1369            sizeof(tng_data->var_num_atoms_flag));
1370     offset += sizeof(tng_data->var_num_atoms_flag);
1371
1372     memcpy(&tng_data->frame_set_n_frames, block->block_contents+offset,
1373            sizeof(tng_data->frame_set_n_frames));
1374     if(tng_data->input_endianness_swap_func_64)
1375     {
1376         if(tng_data->input_endianness_swap_func_64(tng_data,
1377                                                  &tng_data->frame_set_n_frames)
1378             != TNG_SUCCESS)
1379         {
1380             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1381                     __FILE__, __LINE__);
1382         }
1383     }
1384     offset += sizeof(tng_data->frame_set_n_frames);
1385
1386     memcpy(&tng_data->first_trajectory_frame_set_input_file_pos,
1387            block->block_contents+offset,
1388            sizeof(tng_data->first_trajectory_frame_set_input_file_pos));
1389     if(tng_data->input_endianness_swap_func_64)
1390     {
1391         if(tng_data->input_endianness_swap_func_64(tng_data,
1392                           &tng_data->first_trajectory_frame_set_input_file_pos)
1393             != TNG_SUCCESS)
1394         {
1395             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1396                     __FILE__, __LINE__);
1397         }
1398     }
1399     offset += sizeof(tng_data->first_trajectory_frame_set_input_file_pos);
1400
1401     tng_data->current_trajectory_frame_set.next_frame_set_file_pos =
1402     tng_data->first_trajectory_frame_set_input_file_pos;
1403
1404
1405     memcpy(&tng_data->last_trajectory_frame_set_input_file_pos,
1406            block->block_contents+offset,
1407            sizeof(tng_data->last_trajectory_frame_set_input_file_pos));
1408     if(tng_data->input_endianness_swap_func_64)
1409     {
1410         if(tng_data->input_endianness_swap_func_64(tng_data,
1411                           &tng_data->last_trajectory_frame_set_input_file_pos)
1412             != TNG_SUCCESS)
1413         {
1414             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1415                     __FILE__, __LINE__);
1416         }
1417     }
1418     offset += sizeof(tng_data->last_trajectory_frame_set_input_file_pos);
1419
1420     memcpy(&tng_data->medium_stride_length, block->block_contents+offset,
1421            sizeof(tng_data->medium_stride_length));
1422     if(tng_data->input_endianness_swap_func_64)
1423     {
1424         if(tng_data->input_endianness_swap_func_64(tng_data,
1425                                                &tng_data->medium_stride_length)
1426             != TNG_SUCCESS)
1427         {
1428             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1429                     __FILE__, __LINE__);
1430         }
1431     }
1432     offset += sizeof(tng_data->medium_stride_length);
1433
1434     memcpy(&tng_data->long_stride_length, block->block_contents+offset,
1435            sizeof(tng_data->long_stride_length));
1436     if(tng_data->input_endianness_swap_func_64)
1437     {
1438         if(tng_data->input_endianness_swap_func_64(tng_data,
1439                                                  &tng_data->long_stride_length)
1440             != TNG_SUCCESS)
1441         {
1442             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1443                     __FILE__, __LINE__);
1444         }
1445     }
1446     offset += sizeof(tng_data->long_stride_length);
1447
1448     if(block->block_version >= 3)
1449     {
1450         memcpy(&tng_data->distance_unit_exponential, block->block_contents+offset,
1451             sizeof(tng_data->distance_unit_exponential));
1452         if(tng_data->input_endianness_swap_func_64)
1453         {
1454             if(tng_data->input_endianness_swap_func_64(tng_data,
1455                                           &tng_data->distance_unit_exponential)
1456                 != TNG_SUCCESS)
1457             {
1458                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1459                         __FILE__, __LINE__);
1460             }
1461         }
1462     }
1463
1464     return(TNG_SUCCESS);
1465 }
1466
1467 /** Write a general info block. This is the first block of a TNG file.
1468  * @param tng_data is a trajectory data container.
1469  * @param hash_mode is an option to decide whether to use the md5 hash or not.
1470  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
1471  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1472  * error has occured.
1473  */
1474 static tng_function_status tng_general_info_block_write
1475                 (tng_trajectory_t tng_data,
1476                  const char hash_mode)
1477 {
1478     int first_program_name_len, first_user_name_len;
1479     int first_computer_name_len, first_pgp_signature_len;
1480     int last_program_name_len, last_user_name_len;
1481     int last_computer_name_len, last_pgp_signature_len;
1482     int forcefield_name_len, name_len;
1483     int offset = 0;
1484     tng_gen_block_t block;
1485
1486     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
1487     {
1488         return(TNG_CRITICAL);
1489     }
1490
1491     fseek(tng_data->output_file, 0, SEEK_SET);
1492
1493     /* If the strings are unallocated allocate memory for just string
1494      * termination */
1495     if(!tng_data->first_program_name)
1496     {
1497         tng_data->first_program_name = malloc(1);
1498         if(!tng_data->first_program_name)
1499         {
1500             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1501                    __FILE__, __LINE__);
1502             return(TNG_CRITICAL);
1503         }
1504         tng_data->first_program_name[0] = 0;
1505     }
1506     if(!tng_data->last_program_name)
1507     {
1508         tng_data->last_program_name = malloc(1);
1509         if(!tng_data->last_program_name)
1510         {
1511             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1512                    __FILE__, __LINE__);
1513             return(TNG_CRITICAL);
1514         }
1515         tng_data->last_program_name[0] = 0;
1516     }
1517     if(!tng_data->first_user_name)
1518     {
1519         tng_data->first_user_name = malloc(1);
1520         if(!tng_data->first_user_name)
1521         {
1522             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1523                    __FILE__, __LINE__);
1524             return(TNG_CRITICAL);
1525         }
1526         tng_data->first_user_name[0] = 0;
1527     }
1528     if(!tng_data->last_user_name)
1529     {
1530         tng_data->last_user_name = malloc(1);
1531         if(!tng_data->last_user_name)
1532         {
1533             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1534                    __FILE__, __LINE__);
1535             return(TNG_CRITICAL);
1536         }
1537         tng_data->last_user_name[0] = 0;
1538     }
1539     if(!tng_data->first_computer_name)
1540     {
1541         tng_data->first_computer_name = malloc(1);
1542         if(!tng_data->first_computer_name)
1543         {
1544             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1545                    __FILE__, __LINE__);
1546             return(TNG_CRITICAL);
1547         }
1548         tng_data->first_computer_name[0] = 0;
1549     }
1550     if(!tng_data->last_computer_name)
1551     {
1552         tng_data->last_computer_name = malloc(1);
1553         if(!tng_data->last_computer_name)
1554         {
1555             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1556                    __FILE__, __LINE__);
1557             return(TNG_CRITICAL);
1558         }
1559         tng_data->last_computer_name[0] = 0;
1560     }
1561     if(!tng_data->first_pgp_signature)
1562     {
1563         tng_data->first_pgp_signature = malloc(1);
1564         if(!tng_data->first_pgp_signature)
1565         {
1566             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1567                    __FILE__, __LINE__);
1568             return(TNG_CRITICAL);
1569         }
1570         tng_data->first_pgp_signature[0] = 0;
1571     }
1572     if(!tng_data->last_pgp_signature)
1573     {
1574         tng_data->last_pgp_signature = malloc(1);
1575         if(!tng_data->last_pgp_signature)
1576         {
1577             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1578                    __FILE__, __LINE__);
1579             return(TNG_CRITICAL);
1580         }
1581         tng_data->last_pgp_signature[0] = 0;
1582     }
1583     if(!tng_data->forcefield_name)
1584     {
1585         tng_data->forcefield_name = malloc(1);
1586         if(!tng_data->forcefield_name)
1587         {
1588             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1589                    __FILE__, __LINE__);
1590             return(TNG_CRITICAL);
1591         }
1592         tng_data->forcefield_name[0] = 0;
1593     }
1594
1595     tng_block_init(&block);
1596
1597     name_len = (int)strlen("GENERAL INFO");
1598
1599     block->name = malloc(name_len + 1);
1600     if(!block->name)
1601     {
1602         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
1603                 name_len+1, __FILE__, __LINE__);
1604         tng_block_destroy(&block);
1605         return(TNG_CRITICAL);
1606     }
1607
1608     strcpy(block->name, "GENERAL INFO");
1609     block->id = TNG_GENERAL_INFO;
1610
1611     first_program_name_len = tng_min_i((int)strlen(tng_data->first_program_name) + 1,
1612                            TNG_MAX_STR_LEN);
1613     last_program_name_len = tng_min_i((int)strlen(tng_data->last_program_name) + 1,
1614                            TNG_MAX_STR_LEN);
1615     first_user_name_len = tng_min_i((int)strlen(tng_data->first_user_name) + 1,
1616                         TNG_MAX_STR_LEN);
1617     last_user_name_len = tng_min_i((int)strlen(tng_data->last_user_name) + 1,
1618                         TNG_MAX_STR_LEN);
1619     first_computer_name_len = tng_min_i((int)strlen(tng_data->first_computer_name) + 1,
1620                             TNG_MAX_STR_LEN);
1621     last_computer_name_len = tng_min_i((int)strlen(tng_data->last_computer_name) + 1,
1622                             TNG_MAX_STR_LEN);
1623     first_pgp_signature_len = tng_min_i((int)strlen(tng_data->first_pgp_signature) + 1,
1624                             TNG_MAX_STR_LEN);
1625     last_pgp_signature_len = tng_min_i((int)strlen(tng_data->last_pgp_signature) + 1,
1626                             TNG_MAX_STR_LEN);
1627     forcefield_name_len = tng_min_i((int)strlen(tng_data->forcefield_name) + 1,
1628                               TNG_MAX_STR_LEN);
1629
1630     block->block_contents_size = sizeof(tng_data->time) +
1631                 sizeof(tng_data->var_num_atoms_flag) +
1632                 sizeof(tng_data->frame_set_n_frames) +
1633                 sizeof(tng_data->first_trajectory_frame_set_input_file_pos) +
1634                 sizeof(tng_data->last_trajectory_frame_set_input_file_pos) +
1635                 sizeof(tng_data->medium_stride_length) +
1636                 sizeof(tng_data->long_stride_length) +
1637                 sizeof(tng_data->distance_unit_exponential) +
1638                 first_program_name_len +
1639                 last_program_name_len +
1640                 first_user_name_len +
1641                 last_user_name_len +
1642                 first_computer_name_len +
1643                 last_computer_name_len +
1644                 first_pgp_signature_len +
1645                 last_pgp_signature_len +
1646                 forcefield_name_len;
1647
1648     if(block->block_contents)
1649     {
1650         free(block->block_contents);
1651     }
1652     block->block_contents = malloc(block->block_contents_size);
1653     if(!block->block_contents)
1654     {
1655         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
1656                block->block_contents_size, __FILE__, __LINE__);
1657         tng_block_destroy(&block);
1658         return(TNG_CRITICAL);
1659     }
1660
1661     strncpy(block->block_contents, tng_data->first_program_name, first_program_name_len);
1662     offset += first_program_name_len;
1663
1664     strncpy(block->block_contents+offset, tng_data->last_program_name, last_program_name_len);
1665     offset += last_program_name_len;
1666
1667     strncpy(block->block_contents+offset, tng_data->first_user_name, first_user_name_len);
1668     offset += first_user_name_len;
1669
1670     strncpy(block->block_contents+offset, tng_data->last_user_name, last_user_name_len);
1671     offset += last_user_name_len;
1672
1673     strncpy(block->block_contents+offset, tng_data->first_computer_name,
1674             first_computer_name_len);
1675     offset += first_computer_name_len;
1676
1677     strncpy(block->block_contents+offset, tng_data->last_computer_name,
1678             last_computer_name_len);
1679     offset += last_computer_name_len;
1680
1681     strncpy(block->block_contents+offset, tng_data->first_pgp_signature,
1682             first_pgp_signature_len);
1683     offset += first_pgp_signature_len;
1684
1685     strncpy(block->block_contents+offset, tng_data->last_pgp_signature,
1686             last_pgp_signature_len);
1687     offset += last_pgp_signature_len;
1688
1689     strncpy(block->block_contents+offset, tng_data->forcefield_name,
1690             forcefield_name_len);
1691     offset += forcefield_name_len;
1692
1693     memcpy(block->block_contents+offset, &tng_data->time,
1694            sizeof(tng_data->time));
1695     if(tng_data->output_endianness_swap_func_64)
1696     {
1697         if(tng_data->output_endianness_swap_func_64(tng_data,
1698                                       (int64_t *)block->header_contents+offset)
1699             != TNG_SUCCESS)
1700         {
1701             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1702                     __FILE__, __LINE__);
1703         }
1704     }
1705     offset += sizeof(tng_data->time);
1706
1707     memcpy(block->block_contents+offset, &tng_data->var_num_atoms_flag,
1708            sizeof(tng_data->var_num_atoms_flag));
1709     offset += sizeof(tng_data->var_num_atoms_flag);
1710
1711     memcpy(block->block_contents+offset, &tng_data->frame_set_n_frames,
1712            sizeof(tng_data->frame_set_n_frames));
1713     if(tng_data->output_endianness_swap_func_64)
1714     {
1715         if(tng_data->output_endianness_swap_func_64(tng_data,
1716                                       (int64_t *)block->header_contents+offset)
1717             != TNG_SUCCESS)
1718         {
1719             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1720                     __FILE__, __LINE__);
1721         }
1722     }
1723     offset += sizeof(tng_data->frame_set_n_frames);
1724
1725     memcpy(block->block_contents+offset,
1726            &tng_data->first_trajectory_frame_set_input_file_pos,
1727            sizeof(tng_data->first_trajectory_frame_set_input_file_pos));
1728     if(tng_data->output_endianness_swap_func_64)
1729     {
1730         if(tng_data->output_endianness_swap_func_64(tng_data,
1731                                       (int64_t *)block->header_contents+offset)
1732             != TNG_SUCCESS)
1733         {
1734             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1735                     __FILE__, __LINE__);
1736         }
1737     }
1738     offset += sizeof(tng_data->first_trajectory_frame_set_input_file_pos);
1739
1740     memcpy(block->block_contents+offset,
1741            &tng_data->last_trajectory_frame_set_input_file_pos,
1742            sizeof(tng_data->last_trajectory_frame_set_input_file_pos));
1743     if(tng_data->output_endianness_swap_func_64)
1744     {
1745         if(tng_data->output_endianness_swap_func_64(tng_data,
1746                                       (int64_t *)block->header_contents+offset)
1747             != TNG_SUCCESS)
1748         {
1749             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1750                     __FILE__, __LINE__);
1751         }
1752     }
1753     offset += sizeof(tng_data->last_trajectory_frame_set_input_file_pos);
1754
1755     memcpy(block->block_contents+offset, &tng_data->medium_stride_length,
1756            sizeof(tng_data->medium_stride_length));
1757     if(tng_data->output_endianness_swap_func_64)
1758     {
1759         if(tng_data->output_endianness_swap_func_64(tng_data,
1760                                       (int64_t *)block->header_contents+offset)
1761             != TNG_SUCCESS)
1762         {
1763             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1764                     __FILE__, __LINE__);
1765         }
1766     }
1767     offset += sizeof(tng_data->medium_stride_length);
1768
1769     memcpy(block->block_contents+offset, &tng_data->long_stride_length,
1770            sizeof(tng_data->long_stride_length));
1771     if(tng_data->output_endianness_swap_func_64)
1772     {
1773         if(tng_data->output_endianness_swap_func_64(tng_data,
1774                                       (int64_t *)block->header_contents+offset)
1775             != TNG_SUCCESS)
1776         {
1777             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1778                     __FILE__, __LINE__);
1779         }
1780     }
1781     offset += sizeof(tng_data->long_stride_length);
1782
1783     memcpy(block->block_contents+offset, &tng_data->distance_unit_exponential,
1784            sizeof(tng_data->distance_unit_exponential));
1785     if(tng_data->output_endianness_swap_func_64)
1786     {
1787         if(tng_data->output_endianness_swap_func_64(tng_data,
1788                                       (int64_t *)block->header_contents+offset)
1789             != TNG_SUCCESS)
1790         {
1791             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1792                     __FILE__, __LINE__);
1793         }
1794     }
1795
1796     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
1797     {
1798         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
1799                tng_data->output_file_path, __FILE__, __LINE__);
1800         tng_block_destroy(&block);
1801         return(TNG_CRITICAL);
1802     }
1803
1804     if(fwrite(block->block_contents, block->block_contents_size, 1,
1805         tng_data->output_file) != 1)
1806     {
1807         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__, __LINE__);
1808         tng_block_destroy(&block);
1809         return(TNG_CRITICAL);
1810     }
1811
1812     tng_block_destroy(&block);
1813
1814     return(TNG_SUCCESS);
1815 }
1816
1817 /** Read the chain data of a molecules block.
1818  * @param tng_data is a trajectory data container.
1819  * @param block is a general block container.
1820  * @param chain is the chain data container.
1821  * @param offset is the offset of the block input and is updated when reading.
1822  * @return TNG_SUCCESS(0) is successful.
1823  */
1824 static tng_function_status tng_chain_data_read(tng_trajectory_t tng_data,
1825                                                tng_gen_block_t block,
1826                                                tng_chain_t chain,
1827                                                int *offset)
1828 {
1829     int len;
1830
1831     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
1832
1833     memcpy(&chain->id, block->block_contents+*offset,
1834             sizeof(chain->id));
1835     if(tng_data->input_endianness_swap_func_64)
1836     {
1837         if(tng_data->input_endianness_swap_func_64(tng_data,
1838                                                    &chain->id)
1839             != TNG_SUCCESS)
1840         {
1841             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1842                     __FILE__, __LINE__);
1843         }
1844     }
1845     *offset += sizeof(chain->id);
1846
1847     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
1848             TNG_MAX_STR_LEN);
1849     chain->name = malloc(len);
1850     strncpy(chain->name,
1851             block->block_contents+*offset, len);
1852     *offset += len;
1853
1854     memcpy(&chain->n_residues, block->block_contents+*offset,
1855         sizeof(chain->n_residues));
1856     if(tng_data->input_endianness_swap_func_64)
1857     {
1858         if(tng_data->input_endianness_swap_func_64(tng_data,
1859                                                    &chain->n_residues)
1860             != TNG_SUCCESS)
1861         {
1862             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1863                     __FILE__, __LINE__);
1864         }
1865     }
1866     *offset += sizeof(chain->n_residues);
1867
1868     return(TNG_SUCCESS);
1869 }
1870
1871 /** Write the chain data of a molecules block.
1872  * @param tng_data is a trajectory data container.
1873  * @param block is a general block container.
1874  * @param chain is the chain data container.
1875  * @param offset is the offset of the block output and is updated when writing.
1876  * @return TNG_SUCCESS(0) is successful.
1877  */
1878 static tng_function_status tng_chain_data_write(tng_trajectory_t tng_data,
1879                                                 tng_gen_block_t block,
1880                                                 tng_chain_t chain,
1881                                                 int *offset)
1882 {
1883     int len;
1884
1885     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
1886
1887     memcpy(block->block_contents+*offset, &chain->id, sizeof(chain->id));
1888     if(tng_data->output_endianness_swap_func_64)
1889     {
1890         if(tng_data->output_endianness_swap_func_64(tng_data,
1891                                     (int64_t *)block->header_contents+*offset)
1892             != TNG_SUCCESS)
1893         {
1894             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1895                     __FILE__, __LINE__);
1896         }
1897     }
1898     *offset += sizeof(chain->id);
1899
1900     len = tng_min_i((int)strlen(chain->name) + 1, TNG_MAX_STR_LEN);
1901     strncpy(block->block_contents + *offset, chain->name, len);
1902     *offset += len;
1903
1904     memcpy(block->block_contents+*offset, &chain->n_residues,
1905         sizeof(chain->n_residues));
1906     if(tng_data->output_endianness_swap_func_64)
1907     {
1908         if(tng_data->output_endianness_swap_func_64(tng_data,
1909                                     (int64_t *)block->header_contents+*offset)
1910             != TNG_SUCCESS)
1911         {
1912             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1913                     __FILE__, __LINE__);
1914         }
1915     }
1916     *offset += sizeof(chain->n_residues);
1917
1918     return(TNG_SUCCESS);
1919 }
1920
1921 /** Read the residue data of a molecules block.
1922  * @param tng_data is a trajectory data container.
1923  * @param block is a general block container.
1924  * @param residue is the residue data container.
1925  * @param offset is the offset of the block input and is updated when reading.
1926  * @return TNG_SUCCESS(0) is successful.
1927  */
1928 static tng_function_status tng_residue_data_read(tng_trajectory_t tng_data,
1929                                                  tng_gen_block_t block,
1930                                                  tng_residue_t residue,
1931                                                  int *offset)
1932 {
1933     int len;
1934
1935     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
1936
1937     memcpy(&residue->id, block->block_contents+*offset,
1938         sizeof(residue->id));
1939     if(tng_data->input_endianness_swap_func_64)
1940     {
1941         if(tng_data->input_endianness_swap_func_64(tng_data,
1942                                                    &residue->id)
1943             != TNG_SUCCESS)
1944         {
1945             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1946                     __FILE__, __LINE__);
1947         }
1948     }
1949     *offset += sizeof(residue->id);
1950
1951     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
1952             TNG_MAX_STR_LEN);
1953     residue->name = malloc(len);
1954     strncpy(residue->name,
1955             block->block_contents+*offset, len);
1956     *offset += len;
1957
1958     memcpy(&residue->n_atoms, block->block_contents+*offset,
1959             sizeof(residue->n_atoms));
1960     if(tng_data->input_endianness_swap_func_64)
1961     {
1962         if(tng_data->input_endianness_swap_func_64(tng_data,
1963                                                    &residue->n_atoms)
1964             != TNG_SUCCESS)
1965         {
1966             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1967                     __FILE__, __LINE__);
1968         }
1969     }
1970     *offset += sizeof(residue->n_atoms);
1971
1972     return(TNG_SUCCESS);
1973 }
1974
1975 /** Write the residue data of a molecules block.
1976  * @param tng_data is a trajectory data container.
1977  * @param block is a general block container.
1978  * @param residue is the residue data container.
1979  * @param offset is the offset of the block output and is updated when writing.
1980  * @return TNG_SUCCESS(0) is successful.
1981  */
1982 static tng_function_status tng_residue_data_write(tng_trajectory_t tng_data,
1983                                                   tng_gen_block_t block,
1984                                                   tng_residue_t residue,
1985                                                   int *offset)
1986 {
1987     int len;
1988
1989     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
1990
1991     memcpy(block->block_contents+*offset, &residue->id, sizeof(residue->id));
1992     if(tng_data->output_endianness_swap_func_64)
1993     {
1994         if(tng_data->output_endianness_swap_func_64(tng_data,
1995                                     (int64_t *)block->header_contents+*offset)
1996             != TNG_SUCCESS)
1997         {
1998             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1999                     __FILE__, __LINE__);
2000         }
2001     }
2002     *offset += sizeof(residue->id);
2003
2004     len = tng_min_i((int)strlen(residue->name) + 1, TNG_MAX_STR_LEN);
2005     strncpy(block->block_contents + *offset, residue->name, len);
2006     *offset += len;
2007
2008     memcpy(block->block_contents+*offset, &residue->n_atoms,
2009         sizeof(residue->n_atoms));
2010     if(tng_data->output_endianness_swap_func_64)
2011     {
2012         if(tng_data->output_endianness_swap_func_64(tng_data,
2013                                     (int64_t *)block->header_contents+*offset)
2014             != TNG_SUCCESS)
2015         {
2016             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2017                     __FILE__, __LINE__);
2018         }
2019     }
2020     *offset += sizeof(residue->n_atoms);
2021
2022     return(TNG_SUCCESS);
2023 }
2024
2025 /** Read the atom data of a molecules block.
2026  * @param tng_data is a trajectory data container.
2027  * @param block is a general block container.
2028  * @param atom is the atom data container.
2029  * @param offset is the offset of the block input and is updated when reading.
2030  * @return TNG_SUCCESS(0) is successful.
2031  */
2032 static tng_function_status tng_atom_data_read(tng_trajectory_t tng_data,
2033                                               tng_gen_block_t block,
2034                                               tng_atom_t atom,
2035                                               int *offset)
2036 {
2037     int len;
2038
2039     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2040
2041     memcpy(&atom->id, block->block_contents+*offset,
2042         sizeof(atom->id));
2043     if(tng_data->input_endianness_swap_func_64)
2044     {
2045         if(tng_data->input_endianness_swap_func_64(tng_data,
2046                                                     &atom->id)
2047             != TNG_SUCCESS)
2048         {
2049             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2050                     __FILE__, __LINE__);
2051         }
2052     }
2053     *offset += sizeof(atom->id);
2054
2055     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
2056             TNG_MAX_STR_LEN);
2057     atom->name = malloc(len);
2058     strncpy(atom->name,
2059             block->block_contents+*offset, len);
2060     *offset += len;
2061
2062     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
2063             TNG_MAX_STR_LEN);
2064     atom->atom_type = malloc(len);
2065     strncpy(atom->atom_type,
2066             block->block_contents+*offset, len);
2067     *offset += len;
2068
2069     return(TNG_SUCCESS);
2070 }
2071
2072 /** Write the atom data of a molecules block.
2073  * @param tng_data is a trajectory data container.
2074  * @param block is a general block container.
2075  * @param atom is the atom data container.
2076  * @param offset is the offset of the block output and is updated when writing.
2077  * @return TNG_SUCCESS(0) is successful.
2078  */
2079 static tng_function_status tng_atom_data_write(tng_trajectory_t tng_data,
2080                                                tng_gen_block_t block,
2081                                                tng_atom_t atom,
2082                                                int *offset)
2083 {
2084     int len;
2085
2086     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2087
2088     memcpy(block->block_contents+*offset, &atom->id,
2089             sizeof(atom->id));
2090     if(tng_data->output_endianness_swap_func_64)
2091     {
2092         if(tng_data->output_endianness_swap_func_64(tng_data,
2093                                     (int64_t *)block->header_contents+*offset)
2094             != TNG_SUCCESS)
2095         {
2096             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2097                     __FILE__, __LINE__);
2098         }
2099     }
2100     *offset += sizeof(atom->id);
2101
2102     len = tng_min_i((int)strlen(atom->name) + 1, TNG_MAX_STR_LEN);
2103     strncpy(block->block_contents + *offset, atom->name, len);
2104     *offset += len;
2105
2106     len = tng_min_i((int)strlen(atom->atom_type) + 1, TNG_MAX_STR_LEN);
2107     strncpy(block->block_contents + *offset, atom->atom_type, len);
2108     *offset += len;
2109
2110     return(TNG_SUCCESS);
2111 }
2112
2113 /** Read a molecules block. Contains chain, residue and atom data
2114  * @param tng_data is a trajectory data container.
2115  * @param block is a general block container.
2116  * @param hash_mode is an option to decide whether to use the md5 hash or not.
2117  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
2118  * compared to the md5 hash of the read contents to ensure valid data.
2119  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
2120  * error has occured.
2121  */
2122 static tng_function_status tng_molecules_block_read
2123                 (tng_trajectory_t tng_data,
2124                  tng_gen_block_t block,
2125                  const char hash_mode)
2126 {
2127     int64_t i, j, k, l;
2128     int len, offset = 0;
2129     tng_molecule_t molecule;
2130     tng_chain_t chain;
2131     tng_residue_t residue;
2132     tng_atom_t atom;
2133     tng_bond_t bond;
2134     tng_bool same_hash;
2135
2136     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
2137     {
2138         return(TNG_CRITICAL);
2139     }
2140
2141     if(block->block_contents)
2142     {
2143         free(block->block_contents);
2144     }
2145
2146     block->block_contents = malloc(block->block_contents_size);
2147     if(!block->block_contents)
2148     {
2149         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2150                block->block_contents_size, __FILE__, __LINE__);
2151         return(TNG_CRITICAL);
2152     }
2153
2154     /* Read the whole block into block_contents to be able to write it to disk
2155      * even if it cannot be interpreted. */
2156     if(fread(block->block_contents, block->block_contents_size, 1,
2157              tng_data->input_file) == 0)
2158     {
2159         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
2160     }
2161
2162     /* FIXME: Does not check if the size of the contents matches the expected
2163      * size or if the contents can be read. */
2164
2165     if(hash_mode == TNG_USE_HASH)
2166     {
2167         tng_md5_hash_match_verify(block, &same_hash);
2168         if(same_hash != TNG_TRUE)
2169         {
2170             fprintf(stderr, "TNG library: Molecules block contents corrupt. Hashes do not match. "
2171                 "%s: %d\n",
2172                 __FILE__, __LINE__);
2173         }
2174     }
2175
2176     if(tng_data->molecules)
2177     {
2178         for(i=tng_data->n_molecules; i--;)
2179         {
2180             tng_molecule_destroy(tng_data, &tng_data->molecules[i]);
2181         }
2182         free(tng_data->molecules);
2183         tng_data->molecules = 0;
2184         tng_data->n_molecules = 0;
2185     }
2186
2187     memcpy(&tng_data->n_molecules, block->block_contents,
2188            sizeof(tng_data->n_molecules));
2189     if(tng_data->input_endianness_swap_func_64)
2190     {
2191         if(tng_data->input_endianness_swap_func_64(tng_data,
2192                                                    &tng_data->n_molecules)
2193             != TNG_SUCCESS)
2194         {
2195             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2196                     __FILE__, __LINE__);
2197         }
2198     }
2199     offset += sizeof(tng_data->n_molecules);
2200
2201     if(tng_data->molecules)
2202     {
2203         free(tng_data->molecules);
2204     }
2205
2206     tng_data->n_particles = 0;
2207
2208     tng_data->molecules = malloc(tng_data->n_molecules *
2209                           sizeof(struct tng_molecule));
2210     if(!tng_data->molecules)
2211     {
2212         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2213                tng_data->n_molecules * sizeof(struct tng_molecule),
2214                __FILE__, __LINE__);
2215         return(TNG_CRITICAL);
2216     }
2217
2218     if(!tng_data->var_num_atoms_flag)
2219     {
2220         if(tng_data->molecule_cnt_list)
2221         {
2222             free(tng_data->molecule_cnt_list);
2223         }
2224         tng_data->molecule_cnt_list = malloc(sizeof(int64_t) *
2225                                       tng_data->n_molecules);
2226         if(!tng_data->molecule_cnt_list)
2227         {
2228             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2229                    tng_data->n_molecules * sizeof(struct tng_molecule),
2230                    __FILE__, __LINE__);
2231             return(TNG_CRITICAL);
2232         }
2233     }
2234
2235     /* Read each molecule from file */
2236     for(i=0; i < tng_data->n_molecules; i++)
2237     {
2238         molecule = &tng_data->molecules[i];
2239
2240         memcpy(&molecule->id, block->block_contents+offset,
2241                sizeof(molecule->id));
2242         if(tng_data->input_endianness_swap_func_64)
2243         {
2244             if(tng_data->input_endianness_swap_func_64(tng_data,
2245                                                        &molecule->id)
2246                 != TNG_SUCCESS)
2247             {
2248                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2249                         __FILE__, __LINE__);
2250             }
2251         }
2252         offset += sizeof(molecule->id);
2253
2254 /*         fprintf(stderr, "TNG library: Read id: %"PRId64" offset: %d\n", molecule->id, offset);*/
2255         len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2256         molecule->name = malloc(len);
2257         strncpy(molecule->name, block->block_contents+offset, len);
2258         offset += len;
2259
2260         memcpy(&molecule->quaternary_str, block->block_contents+offset,
2261                sizeof(molecule->quaternary_str));
2262         if(tng_data->input_endianness_swap_func_64)
2263         {
2264             if(tng_data->input_endianness_swap_func_64(tng_data,
2265                                                      &molecule->quaternary_str)
2266                 != TNG_SUCCESS)
2267             {
2268                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2269                         __FILE__, __LINE__);
2270             }
2271         }
2272         offset += sizeof(molecule->quaternary_str);
2273
2274         if(!tng_data->var_num_atoms_flag)
2275         {
2276             memcpy(&tng_data->molecule_cnt_list[i],
2277                    block->block_contents+offset,
2278                    sizeof(int64_t));
2279             if(tng_data->input_endianness_swap_func_64)
2280             {
2281                 if(tng_data->input_endianness_swap_func_64(tng_data,
2282                                                &tng_data->molecule_cnt_list[i])
2283                     != TNG_SUCCESS)
2284                 {
2285                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2286                             __FILE__, __LINE__);
2287                 }
2288             }
2289             offset += sizeof(int64_t);
2290         }
2291
2292
2293         memcpy(&molecule->n_chains, block->block_contents+offset,
2294                sizeof(molecule->n_chains));
2295         if(tng_data->input_endianness_swap_func_64)
2296         {
2297             if(tng_data->input_endianness_swap_func_64(tng_data,
2298                                                        &molecule->n_chains)
2299                 != TNG_SUCCESS)
2300             {
2301                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2302                         __FILE__, __LINE__);
2303             }
2304         }
2305         offset += sizeof(molecule->n_chains);
2306
2307         memcpy(&molecule->n_residues, block->block_contents+offset,
2308                sizeof(molecule->n_residues));
2309         if(tng_data->input_endianness_swap_func_64)
2310         {
2311             if(tng_data->input_endianness_swap_func_64(tng_data,
2312                                                        &molecule->n_residues)
2313                 != TNG_SUCCESS)
2314             {
2315                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2316                         __FILE__, __LINE__);
2317             }
2318         }
2319         offset += sizeof(molecule->n_residues);
2320
2321         memcpy(&molecule->n_atoms, block->block_contents+offset,
2322                sizeof(molecule->n_atoms));
2323         if(tng_data->input_endianness_swap_func_64)
2324         {
2325             if(tng_data->input_endianness_swap_func_64(tng_data,
2326                                                        &molecule->n_atoms)
2327                 != TNG_SUCCESS)
2328             {
2329                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2330                         __FILE__, __LINE__);
2331             }
2332         }
2333         offset += sizeof(molecule->n_atoms);
2334
2335         tng_data->n_particles += molecule->n_atoms *
2336                                  tng_data->molecule_cnt_list[i];
2337
2338         if(molecule->n_chains > 0)
2339         {
2340             molecule->chains = malloc(molecule->n_chains *
2341                                     sizeof(struct tng_chain));
2342             if(!molecule->chains)
2343             {
2344                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2345                     molecule->n_chains * sizeof(struct tng_chain),
2346                     __FILE__, __LINE__);
2347                 return(TNG_CRITICAL);
2348             }
2349
2350             chain = molecule->chains;
2351         }
2352         else
2353         {
2354             chain = 0;
2355         }
2356
2357         if(molecule->n_residues > 0)
2358         {
2359             molecule->residues = malloc(molecule->n_residues *
2360                                 sizeof(struct tng_residue));
2361             if(!molecule->residues)
2362             {
2363                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2364                     molecule->n_residues * sizeof(struct tng_residue),
2365                     __FILE__, __LINE__);
2366                 if(molecule->chains)
2367                 {
2368                     free(molecule->chains);
2369                     molecule->chains = 0;
2370                 }
2371                 return(TNG_CRITICAL);
2372             }
2373
2374             residue = molecule->residues;
2375         }
2376         else
2377         {
2378             residue = 0;
2379         }
2380
2381         molecule->atoms = malloc(molecule->n_atoms *
2382                                  sizeof(struct tng_atom));
2383         if(!molecule->atoms)
2384         {
2385             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2386                    molecule->n_atoms * sizeof(struct tng_atom),
2387                    __FILE__, __LINE__);
2388             if(molecule->chains)
2389             {
2390                 free(molecule->chains);
2391                 molecule->chains = 0;
2392             }
2393             if(molecule->residues)
2394             {
2395                 free(molecule->residues);
2396                 molecule->residues = 0;
2397             }
2398             return(TNG_CRITICAL);
2399         }
2400
2401         atom = molecule->atoms;
2402
2403         if(molecule->n_chains > 0)
2404         {
2405             /* Read the chains of the molecule */
2406             for(j=molecule->n_chains; j--;)
2407             {
2408                 chain->molecule = molecule;
2409
2410                 tng_chain_data_read(tng_data, block, chain, &offset);
2411
2412                 chain->residues = molecule->residues;
2413                 residue = chain->residues;
2414
2415                 /* Read the residues of the chain */
2416                 for(k=chain->n_residues; k--;)
2417                 {
2418                     residue->chain = chain;
2419
2420                     tng_residue_data_read(tng_data, block, residue, &offset);
2421
2422                     residue->atoms_offset = atom - molecule->atoms;
2423                     /* Read the atoms of the residue */
2424                     for(l=residue->n_atoms; l--;)
2425                     {
2426                         atom->residue = residue;
2427
2428                         tng_atom_data_read(tng_data, block, atom, &offset);
2429
2430                         atom++;
2431                     }
2432                     residue++;
2433                 }
2434                 chain++;
2435             }
2436         }
2437         else
2438         {
2439             if(molecule->n_residues > 0)
2440             {
2441                 for(k=molecule->n_residues; k--;)
2442                 {
2443                     residue->chain = 0;
2444
2445                     tng_residue_data_read(tng_data, block, residue, &offset);
2446
2447                     residue->atoms_offset = atom - molecule->atoms;
2448                     /* Read the atoms of the residue */
2449                     for(l=residue->n_atoms; l--;)
2450                     {
2451                         atom->residue = residue;
2452
2453                         tng_atom_data_read(tng_data, block, atom, &offset);
2454
2455                         atom++;
2456                     }
2457                     residue++;
2458                 }
2459             }
2460             else
2461             {
2462                 for(l=molecule->n_atoms; l--;)
2463                 {
2464                     atom->residue = 0;
2465
2466                     tng_atom_data_read(tng_data, block, atom, &offset);
2467
2468                     atom++;
2469                 }
2470             }
2471         }
2472
2473         memcpy(&molecule->n_bonds, block->block_contents+offset,
2474                sizeof(molecule->n_bonds));
2475         if(tng_data->input_endianness_swap_func_64)
2476         {
2477             if(tng_data->input_endianness_swap_func_64(tng_data,
2478                                                        &molecule->n_bonds)
2479                 != TNG_SUCCESS)
2480             {
2481                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2482                         __FILE__, __LINE__);
2483             }
2484         }
2485         offset += sizeof(molecule->n_bonds);
2486
2487         if(molecule->n_bonds > 0)
2488         {
2489             tng_data->molecules[i].bonds = malloc(molecule->n_bonds *
2490                                            sizeof(struct tng_bond));
2491             if(!molecule->bonds)
2492             {
2493                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2494                        molecule->n_bonds * sizeof(struct tng_bond),
2495                        __FILE__, __LINE__);
2496                 if(molecule->chains)
2497                 {
2498                     free(molecule->chains);
2499                     molecule->chains = 0;
2500                 }
2501                 if(molecule->residues)
2502                 {
2503                     free(molecule->residues);
2504                     molecule->residues = 0;
2505                 }
2506                 if(molecule->atoms)
2507                 {
2508                     free(molecule->atoms);
2509                     molecule->atoms = 0;
2510                 }
2511                 return(TNG_CRITICAL);
2512             }
2513
2514             bond = molecule->bonds;
2515
2516             for(j=molecule->n_bonds; j--;)
2517             {
2518                 memcpy(&bond->from_atom_id, block->block_contents+offset,
2519                     sizeof(bond->from_atom_id));
2520                 if(tng_data->input_endianness_swap_func_64)
2521                 {
2522                     if(tng_data->input_endianness_swap_func_64(tng_data,
2523                                                                &bond->from_atom_id)
2524                         != TNG_SUCCESS)
2525                     {
2526                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2527                                 __FILE__, __LINE__);
2528                     }
2529                 }
2530                 offset += sizeof(bond->from_atom_id);
2531
2532                 memcpy(&bond->to_atom_id, block->block_contents+offset,
2533                     sizeof(bond->to_atom_id));
2534                 if(tng_data->input_endianness_swap_func_64)
2535                 {
2536                     if(tng_data->input_endianness_swap_func_64(tng_data,
2537                                                                &bond->to_atom_id)
2538                         != TNG_SUCCESS)
2539                     {
2540                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2541                                 __FILE__, __LINE__);
2542                     }
2543                 }
2544                 offset += sizeof(bond->to_atom_id);
2545
2546                 bond++;
2547             }
2548         }
2549         else
2550         {
2551             molecule->bonds = 0;
2552         }
2553     }
2554
2555     return(TNG_SUCCESS);
2556 }
2557
2558 /** Write a molecules block.
2559  * @param tng_data is a trajectory data container.
2560  * @param hash_mode is an option to decide whether to use the md5 hash or not.
2561  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
2562  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
2563  * error has occured.
2564  */
2565 static tng_function_status tng_molecules_block_write
2566                 (tng_trajectory_t tng_data,
2567                  const char hash_mode)
2568 {
2569     int len = 0, name_len, offset = 0;
2570     int64_t i, j, k, l;
2571     tng_molecule_t molecule;
2572     tng_chain_t chain;
2573     tng_residue_t residue;
2574     tng_atom_t atom;
2575     tng_bond_t bond;
2576     tng_gen_block_t block;
2577
2578     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
2579     {
2580         return(TNG_CRITICAL);
2581     }
2582
2583     /* First predict the size of the block */
2584     for(i = 0; i < tng_data->n_molecules; i++)
2585     {
2586         molecule = &tng_data->molecules[i];
2587         if(!molecule->name)
2588         {
2589             molecule->name = malloc(1);
2590             if(!molecule->name)
2591             {
2592                 fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2593                        __FILE__, __LINE__);
2594                 return(TNG_CRITICAL);
2595             }
2596             molecule->name[0] = 0;
2597         }
2598         len += tng_min_i((int)strlen(molecule->name) + 1, TNG_MAX_STR_LEN);
2599
2600         chain = molecule->chains;
2601         for(j = molecule->n_chains; j--;)
2602         {
2603             len += sizeof(chain->id);
2604
2605             if(!chain->name)
2606             {
2607                 chain->name = malloc(1);
2608                 if(!chain->name)
2609                 {
2610                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2611                            __FILE__, __LINE__);
2612                     return(TNG_CRITICAL);
2613                 }
2614                 chain->name[0] = 0;
2615             }
2616             len += tng_min_i((int)strlen(chain->name) + 1, TNG_MAX_STR_LEN);
2617
2618             len += sizeof(chain->n_residues);
2619
2620             chain++;
2621         }
2622
2623         residue = molecule->residues;
2624         for(j = molecule->n_residues; j--;)
2625         {
2626             len += sizeof(residue->id);
2627
2628             if(!residue->name)
2629             {
2630                 residue->name = malloc(1);
2631                 if(!residue->name)
2632                 {
2633                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2634                            __FILE__, __LINE__);
2635                     return(TNG_CRITICAL);
2636                 }
2637                 residue->name[0] = 0;
2638             }
2639             len += tng_min_i((int)strlen(residue->name) + 1, TNG_MAX_STR_LEN);
2640
2641             len += sizeof(residue->n_atoms);
2642
2643             residue++;
2644         }
2645
2646         atom = molecule->atoms;
2647         for(j = molecule->n_atoms; j--;)
2648         {
2649             len += sizeof(atom->id);
2650             if(!atom->name)
2651             {
2652                 atom->name = malloc(1);
2653                 if(!atom->name)
2654                 {
2655                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2656                            __FILE__, __LINE__);
2657                     return(TNG_CRITICAL);
2658                 }
2659                 atom->name[0] = 0;
2660             }
2661             len += tng_min_i((int)strlen(atom->name) + 1, TNG_MAX_STR_LEN);
2662
2663             if(!atom->atom_type)
2664             {
2665                 atom->atom_type = malloc(1);
2666                 if(!atom->atom_type)
2667                 {
2668                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2669                            __FILE__, __LINE__);
2670                     return(TNG_CRITICAL);
2671                 }
2672                 atom->atom_type[0] = 0;
2673             }
2674             len += tng_min_i((int)strlen(atom->atom_type) + 1, TNG_MAX_STR_LEN);
2675
2676             atom++;
2677         }
2678
2679         for(j = molecule->n_bonds; j--;)
2680         {
2681             len += sizeof(bond->from_atom_id) + sizeof(bond->to_atom_id);
2682         }
2683     }
2684
2685     tng_block_init(&block);
2686
2687     name_len = (int)strlen("MOLECULES");
2688
2689     block->name = malloc(name_len + 1);
2690     if(!block->name)
2691     {
2692         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
2693                 name_len+1, __FILE__, __LINE__);
2694         tng_block_destroy(&block);
2695         return(TNG_CRITICAL);
2696     }
2697
2698     strcpy(block->name, "MOLECULES");
2699     block->id = TNG_MOLECULES;
2700
2701     block->block_contents_size = sizeof(tng_data->n_molecules) +
2702                                  (sizeof(molecule->id) +
2703                                  sizeof(molecule->quaternary_str) +
2704                                  sizeof(molecule->n_chains) +
2705                                  sizeof(molecule->n_residues) +
2706                                  sizeof(molecule->n_atoms) +
2707                                  sizeof(molecule->n_bonds)) *
2708                                  tng_data->n_molecules +
2709                                  len;
2710
2711     if(!tng_data->var_num_atoms_flag)
2712     {
2713         block->block_contents_size += tng_data->n_molecules * sizeof(int64_t);
2714     }
2715
2716     block->block_contents = malloc(block->block_contents_size);
2717     if(!block->block_contents)
2718     {
2719         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2720                block->block_contents_size, __FILE__, __LINE__);
2721         tng_block_destroy(&block);
2722         return(TNG_CRITICAL);
2723     }
2724
2725     memcpy(block->block_contents+offset, &tng_data->n_molecules,
2726            sizeof(tng_data->n_molecules));
2727     if(tng_data->output_endianness_swap_func_64)
2728     {
2729         if(tng_data->output_endianness_swap_func_64(tng_data,
2730                                       (int64_t *)block->header_contents+offset)
2731             != TNG_SUCCESS)
2732         {
2733             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2734                     __FILE__, __LINE__);
2735         }
2736     }
2737     offset += sizeof(tng_data->n_molecules);
2738
2739     for(i = 0; i < tng_data->n_molecules; i++)
2740     {
2741         molecule = &tng_data->molecules[i];
2742         memcpy(block->block_contents+offset, &molecule->id,
2743                sizeof(molecule->id));
2744         if(tng_data->output_endianness_swap_func_64)
2745         {
2746             if(tng_data->output_endianness_swap_func_64(tng_data,
2747                                         (int64_t *)block->header_contents+offset)
2748                 != TNG_SUCCESS)
2749             {
2750                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2751                         __FILE__, __LINE__);
2752             }
2753         }
2754         offset += sizeof(molecule->id);
2755
2756 /*         fprintf(stderr, "TNG library: Wrote id: %"PRId64" offset: %d\n", molecule->id, offset); */
2757         len = tng_min_i((int)strlen(molecule->name) + 1, TNG_MAX_STR_LEN);
2758         strncpy(block->block_contents + offset, molecule->name, len);
2759         offset += len;
2760
2761         memcpy(block->block_contents+offset, &molecule->quaternary_str,
2762                sizeof(molecule->quaternary_str));
2763         if(tng_data->output_endianness_swap_func_64)
2764         {
2765             if(tng_data->output_endianness_swap_func_64(tng_data,
2766                                         (int64_t *)block->header_contents+offset)
2767                 != TNG_SUCCESS)
2768             {
2769                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2770                         __FILE__, __LINE__);
2771             }
2772         }
2773         offset += sizeof(molecule->quaternary_str);
2774
2775         if(!tng_data->var_num_atoms_flag)
2776         {
2777             memcpy(block->block_contents+offset,
2778                    &tng_data->molecule_cnt_list[i], sizeof(int64_t));
2779             if(tng_data->output_endianness_swap_func_64)
2780             {
2781                 if(tng_data->output_endianness_swap_func_64(tng_data,
2782                                             (int64_t *)block->header_contents+offset)
2783                     != TNG_SUCCESS)
2784                 {
2785                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2786                             __FILE__, __LINE__);
2787                 }
2788             }
2789             offset += sizeof(int64_t);
2790         }
2791
2792         memcpy(block->block_contents+offset, &molecule->n_chains,
2793                sizeof(molecule->n_chains));
2794         if(tng_data->output_endianness_swap_func_64)
2795         {
2796             if(tng_data->output_endianness_swap_func_64(tng_data,
2797                                         (int64_t *)block->header_contents+offset)
2798                 != TNG_SUCCESS)
2799             {
2800                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2801                         __FILE__, __LINE__);
2802             }
2803         }
2804         offset += sizeof(molecule->n_chains);
2805
2806         memcpy(block->block_contents+offset, &molecule->n_residues,
2807                sizeof(molecule->n_residues));
2808         if(tng_data->output_endianness_swap_func_64)
2809         {
2810             if(tng_data->output_endianness_swap_func_64(tng_data,
2811                                         (int64_t *)block->header_contents+offset)
2812                 != TNG_SUCCESS)
2813             {
2814                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2815                         __FILE__, __LINE__);
2816             }
2817         }
2818         offset += sizeof(molecule->n_residues);
2819
2820         memcpy(block->block_contents+offset, &molecule->n_atoms,
2821                sizeof(molecule->n_atoms));
2822         if(tng_data->output_endianness_swap_func_64)
2823         {
2824             if(tng_data->output_endianness_swap_func_64(tng_data,
2825                                         (int64_t *)block->header_contents+offset)
2826                 != TNG_SUCCESS)
2827             {
2828                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2829                         __FILE__, __LINE__);
2830             }
2831         }
2832         offset += sizeof(molecule->n_atoms);
2833
2834         if(molecule->n_chains > 0)
2835         {
2836             chain = molecule->chains;
2837             for(j = molecule->n_chains; j--;)
2838             {
2839                 tng_chain_data_write(tng_data, block, chain, &offset);
2840
2841                 residue = chain->residues;
2842                 for(k = chain->n_residues; k--;)
2843                 {
2844                     tng_residue_data_write(tng_data, block, residue, &offset);
2845
2846                     atom = molecule->atoms + residue->atoms_offset;
2847                     for(l = residue->n_atoms; l--;)
2848                     {
2849                         tng_atom_data_write(tng_data, block, atom, &offset);
2850
2851                         atom++;
2852                     }
2853                     residue++;
2854                 }
2855                 chain++;
2856             }
2857         }
2858         else
2859         {
2860             if(molecule->n_residues > 0)
2861             {
2862                 residue = molecule->residues;
2863                 for(k = molecule->n_residues; k--;)
2864                 {
2865                     tng_residue_data_write(tng_data, block, residue, &offset);
2866
2867                     atom = molecule->atoms + residue->atoms_offset;
2868                     for(l = residue->n_atoms; l--;)
2869                     {
2870                         tng_atom_data_write(tng_data, block, atom, &offset);
2871
2872                         atom++;
2873                     }
2874                     residue++;
2875                 }
2876             }
2877             else
2878             {
2879                 atom = molecule->atoms;
2880                 for(l = molecule->n_atoms; l--;)
2881                 {
2882                     tng_atom_data_write(tng_data, block, atom, &offset);
2883
2884                     atom++;
2885                 }
2886             }
2887         }
2888
2889         memcpy(block->block_contents+offset, &molecule->n_bonds,
2890                sizeof(molecule->n_bonds));
2891         if(tng_data->output_endianness_swap_func_64)
2892         {
2893             if(tng_data->output_endianness_swap_func_64(tng_data,
2894                                         (int64_t *)block->header_contents+offset)
2895                 != TNG_SUCCESS)
2896             {
2897                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2898                         __FILE__, __LINE__);
2899             }
2900         }
2901         offset += sizeof(molecule->n_bonds);
2902
2903         bond = molecule->bonds;
2904         for(j = molecule->n_bonds; j--;)
2905         {
2906             memcpy(block->block_contents+offset, &bond->from_atom_id,
2907                    sizeof(bond->from_atom_id));
2908             if(tng_data->output_endianness_swap_func_64)
2909             {
2910                 if(tng_data->output_endianness_swap_func_64(tng_data,
2911                                             (int64_t *)block->header_contents+offset)
2912                     != TNG_SUCCESS)
2913                 {
2914                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2915                             __FILE__, __LINE__);
2916                 }
2917             }
2918             offset += sizeof(bond->from_atom_id);
2919
2920             memcpy(block->block_contents+offset, &bond->to_atom_id,
2921                    sizeof(bond->to_atom_id));
2922             if(tng_data->output_endianness_swap_func_64)
2923             {
2924                 if(tng_data->output_endianness_swap_func_64(tng_data,
2925                                             (int64_t *)block->header_contents+offset)
2926                     != TNG_SUCCESS)
2927                 {
2928                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2929                             __FILE__, __LINE__);
2930                 }
2931             }
2932             offset += sizeof(bond->to_atom_id);
2933
2934             bond++;
2935         }
2936     }
2937
2938     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
2939     {
2940         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
2941                tng_data->output_file_path, __FILE__, __LINE__);
2942         tng_block_destroy(&block);
2943         return(TNG_CRITICAL);
2944     }
2945
2946     if(fwrite(block->block_contents, block->block_contents_size, 1,
2947               tng_data->output_file) != 1)
2948     {
2949         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n",
2950                __FILE__, __LINE__);
2951         tng_block_destroy(&block);
2952         return(TNG_CRITICAL);
2953     }
2954
2955     tng_block_destroy(&block);
2956
2957     return(TNG_SUCCESS);
2958 }
2959
2960 /** Read a frame set block. Update tng_data->current_trajectory_frame_set
2961  * @param tng_data is a trajectory data container.
2962  * @param block is a general block container.
2963  * @param hash_mode is an option to decide whether to use the md5 hash or not.
2964  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
2965  * compared to the md5 hash of the read contents to ensure valid data.
2966  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
2967  * error has occured.
2968  */
2969 static tng_function_status tng_frame_set_block_read
2970                 (tng_trajectory_t tng_data,
2971                  tng_gen_block_t block,
2972                  const char hash_mode)
2973 {
2974     long file_pos;
2975     int offset = 0;
2976     int64_t i, prev_n_particles;
2977     tng_bool same_hash;
2978     tng_trajectory_frame_set_t frame_set =
2979     &tng_data->current_trajectory_frame_set;
2980
2981     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
2982     {
2983         return(TNG_CRITICAL);
2984     }
2985
2986     if(block->block_contents)
2987     {
2988         free(block->block_contents);
2989     }
2990
2991     block->block_contents = malloc(block->block_contents_size);
2992     if(!block->block_contents)
2993     {
2994         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2995                block->block_contents_size, __FILE__, __LINE__);
2996         return(TNG_CRITICAL);
2997     }
2998
2999     /* Read the whole block into block_contents to be able to write it to
3000      * disk even if it cannot be interpreted. */
3001     if(fread(block->block_contents, block->block_contents_size, 1,
3002              tng_data->input_file) == 0)
3003     {
3004         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
3005         return(TNG_CRITICAL);
3006     }
3007
3008     /* FIXME: Does not check if the size of the contents matches the expected
3009      * size or if the contents can be read. */
3010
3011     file_pos = (int64_t)ftell(tng_data->input_file) -
3012                (long)(block->block_contents_size + block->header_contents_size);
3013
3014     if(hash_mode == TNG_USE_HASH)
3015     {
3016         tng_md5_hash_match_verify(block, &same_hash);
3017         if(same_hash != TNG_TRUE)
3018         {
3019             fprintf(stderr, "TNG library: Frame set block contents corrupt. File pos %ld Hashes do not match. "
3020                 "%s: %d\n",
3021                 file_pos, __FILE__, __LINE__);
3022     /*         return(TNG_FAILURE); */
3023         }
3024     }
3025
3026     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
3027
3028     tng_frame_set_particle_mapping_free(tng_data);
3029
3030     if(tng_data->first_trajectory_frame_set_input_file_pos <= 0)
3031     {
3032         tng_data->first_trajectory_frame_set_input_file_pos = file_pos;
3033     }
3034     /* FIXME: Should check the frame number instead of the file_pos, in case
3035      * frame sets are not in order */
3036     if(tng_data->last_trajectory_frame_set_input_file_pos < file_pos)
3037     {
3038         tng_data->last_trajectory_frame_set_input_file_pos = file_pos;
3039     }
3040
3041     memcpy(&frame_set->first_frame, block->block_contents,
3042            sizeof(frame_set->first_frame));
3043     if(tng_data->input_endianness_swap_func_64)
3044     {
3045         if(tng_data->input_endianness_swap_func_64(tng_data,
3046                                                    &frame_set->first_frame)
3047             != TNG_SUCCESS)
3048         {
3049             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3050                     __FILE__, __LINE__);
3051         }
3052     }
3053     offset += sizeof(frame_set->first_frame);
3054
3055     memcpy(&frame_set->n_frames, block->block_contents + offset,
3056            sizeof(frame_set->n_frames));
3057     if(tng_data->input_endianness_swap_func_64)
3058     {
3059         if(tng_data->input_endianness_swap_func_64(tng_data,
3060                                                    &frame_set->n_frames)
3061             != TNG_SUCCESS)
3062         {
3063             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3064                     __FILE__, __LINE__);
3065         }
3066     }
3067     offset += sizeof(frame_set->n_frames);
3068
3069     if(tng_data->var_num_atoms_flag)
3070     {
3071         prev_n_particles = frame_set->n_particles;
3072         frame_set->n_particles = 0;
3073         /* If the list of molecule counts has already been created assume that
3074          * it is of correct size. */
3075         if(!frame_set->molecule_cnt_list)
3076         {
3077                 frame_set->molecule_cnt_list =
3078                 malloc(sizeof(int64_t) * tng_data->n_molecules);
3079
3080                 if(!frame_set->molecule_cnt_list)
3081                 {
3082                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3083                            sizeof(int64_t) * tng_data->n_molecules,
3084                            __FILE__, __LINE__);
3085                     return(TNG_CRITICAL);
3086                 }
3087         }
3088         for(i = 0; i < tng_data->n_molecules; i++)
3089         {
3090             memcpy(&frame_set->molecule_cnt_list[i],
3091                    block->block_contents + offset,
3092                    sizeof(int64_t));
3093             if(tng_data->input_endianness_swap_func_64)
3094             {
3095                 if(tng_data->input_endianness_swap_func_64(tng_data,
3096                                               &frame_set->molecule_cnt_list[i])
3097                     != TNG_SUCCESS)
3098                 {
3099                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3100                             __FILE__, __LINE__);
3101                 }
3102             }
3103             offset += sizeof(int64_t);
3104             frame_set->n_particles += tng_data->molecules[i].n_atoms *
3105                                       frame_set->molecule_cnt_list[i];
3106         }
3107         if(prev_n_particles && frame_set->n_particles != prev_n_particles)
3108         {
3109             /* FIXME: Particle dependent data memory management */
3110         }
3111     }
3112
3113     memcpy(&frame_set->next_frame_set_file_pos,
3114            block->block_contents + offset,
3115            sizeof(frame_set->next_frame_set_file_pos));
3116     if(tng_data->input_endianness_swap_func_64)
3117     {
3118         if(tng_data->input_endianness_swap_func_64(tng_data,
3119                                            &frame_set->next_frame_set_file_pos)
3120             != TNG_SUCCESS)
3121         {
3122             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3123                     __FILE__, __LINE__);
3124         }
3125     }
3126     offset += sizeof(frame_set->next_frame_set_file_pos);
3127
3128     memcpy(&frame_set->prev_frame_set_file_pos,
3129            block->block_contents + offset,
3130            sizeof(frame_set->prev_frame_set_file_pos));
3131     if(tng_data->input_endianness_swap_func_64)
3132     {
3133         if(tng_data->input_endianness_swap_func_64(tng_data,
3134                                            &frame_set->prev_frame_set_file_pos)
3135             != TNG_SUCCESS)
3136         {
3137             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3138                     __FILE__, __LINE__);
3139         }
3140     }
3141     offset += sizeof(frame_set->prev_frame_set_file_pos);
3142
3143     memcpy(&frame_set->medium_stride_next_frame_set_file_pos,
3144            block->block_contents + offset,
3145            sizeof(frame_set->medium_stride_next_frame_set_file_pos));
3146     if(tng_data->input_endianness_swap_func_64)
3147     {
3148         if(tng_data->input_endianness_swap_func_64(tng_data,
3149                              &frame_set->medium_stride_next_frame_set_file_pos)
3150             != TNG_SUCCESS)
3151         {
3152             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3153                     __FILE__, __LINE__);
3154         }
3155     }
3156     offset += sizeof(frame_set->medium_stride_next_frame_set_file_pos);
3157
3158     memcpy(&frame_set->medium_stride_prev_frame_set_file_pos,
3159            block->block_contents + offset,
3160            sizeof(frame_set->medium_stride_prev_frame_set_file_pos));
3161     if(tng_data->input_endianness_swap_func_64)
3162     {
3163         if(tng_data->input_endianness_swap_func_64(tng_data,
3164                              &frame_set->medium_stride_prev_frame_set_file_pos)
3165             != TNG_SUCCESS)
3166         {
3167             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3168                     __FILE__, __LINE__);
3169         }
3170     }
3171     offset += sizeof(frame_set->medium_stride_prev_frame_set_file_pos);
3172
3173     memcpy(&frame_set->long_stride_next_frame_set_file_pos,
3174            block->block_contents + offset,
3175            sizeof(frame_set->long_stride_next_frame_set_file_pos));
3176     if(tng_data->input_endianness_swap_func_64)
3177     {
3178         if(tng_data->input_endianness_swap_func_64(tng_data,
3179                                &frame_set->long_stride_next_frame_set_file_pos)
3180             != TNG_SUCCESS)
3181         {
3182             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3183                     __FILE__, __LINE__);
3184         }
3185     }
3186     offset += sizeof(frame_set->long_stride_next_frame_set_file_pos);
3187
3188     memcpy(&frame_set->long_stride_prev_frame_set_file_pos,
3189            block->block_contents + offset,
3190            sizeof(frame_set->long_stride_prev_frame_set_file_pos));
3191     if(tng_data->input_endianness_swap_func_64)
3192     {
3193         if(tng_data->input_endianness_swap_func_64(tng_data,
3194                                &frame_set->long_stride_prev_frame_set_file_pos)
3195             != TNG_SUCCESS)
3196         {
3197             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3198                     __FILE__, __LINE__);
3199         }
3200     }
3201     offset += sizeof(frame_set->long_stride_prev_frame_set_file_pos);
3202
3203     if(block->block_version >= 3)
3204     {
3205         memcpy(&frame_set->first_frame_time,
3206             block->block_contents + offset,
3207             sizeof(frame_set->first_frame_time));
3208         if(tng_data->input_endianness_swap_func_64)
3209         {
3210             if(tng_data->input_endianness_swap_func_64(tng_data,
3211                                 (int64_t *)&frame_set->first_frame_time)
3212                 != TNG_SUCCESS)
3213             {
3214                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3215                         __FILE__, __LINE__);
3216             }
3217         }
3218         offset += sizeof(frame_set->first_frame_time);
3219
3220         memcpy(&tng_data->time_per_frame,
3221             block->block_contents + offset,
3222             sizeof(tng_data->time_per_frame));
3223         if(tng_data->input_endianness_swap_func_64)
3224         {
3225             if(tng_data->input_endianness_swap_func_64(tng_data,
3226                                 (int64_t *)&tng_data->time_per_frame)
3227                 != TNG_SUCCESS)
3228             {
3229                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3230                         __FILE__, __LINE__);
3231             }
3232         }
3233     }
3234     else
3235     {
3236         frame_set->first_frame_time = -1;
3237         tng_data->time_per_frame = -1;
3238     }
3239
3240     frame_set->n_written_frames = frame_set->n_frames;
3241
3242     return(TNG_SUCCESS);
3243 }
3244
3245 /** Write tng_data->current_trajectory_frame_set to file
3246  * @param tng_data is a trajectory data container.
3247  * @param block is a general block container.
3248  * @param hash_mode is an option to decide whether to use the md5 hash or not.
3249  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
3250  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3251  * error has occured.
3252  */
3253 static tng_function_status tng_frame_set_block_write
3254                 (tng_trajectory_t tng_data,
3255                  tng_gen_block_t block,
3256                  const char hash_mode)
3257 {
3258     char *temp_name;
3259     int64_t i;
3260     int offset = 0;
3261     unsigned int name_len;
3262     tng_trajectory_frame_set_t frame_set =
3263     &tng_data->current_trajectory_frame_set;
3264
3265     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
3266     {
3267         return(TNG_CRITICAL);
3268     }
3269
3270     name_len = (int)strlen("TRAJECTORY FRAME SET");
3271
3272     if(!block->name || strlen(block->name) < name_len)
3273     {
3274         temp_name = realloc(block->name, name_len + 1);
3275         if(!temp_name)
3276         {
3277             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
3278                    name_len+1, __FILE__, __LINE__);
3279             free(block->name);
3280             block->name = 0;
3281             return(TNG_CRITICAL);
3282         }
3283         block->name = temp_name;
3284     }
3285     strcpy(block->name, "TRAJECTORY FRAME SET");
3286     block->id = TNG_TRAJECTORY_FRAME_SET;
3287
3288     block->block_contents_size = sizeof(int64_t) * 8;
3289     block->block_contents_size += sizeof(double) * 2;
3290
3291     if(tng_data->var_num_atoms_flag)
3292     {
3293         block->block_contents_size += sizeof(int64_t) * tng_data->n_molecules;
3294     }
3295
3296     if(block->block_contents)
3297     {
3298         free(block->block_contents);
3299     }
3300     block->block_contents = malloc(block->block_contents_size);
3301     if(!block->block_contents)
3302     {
3303         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3304                block->block_contents_size, __FILE__, __LINE__);
3305         return(TNG_CRITICAL);
3306     }
3307
3308     memcpy(block->block_contents, &frame_set->first_frame,
3309            sizeof(frame_set->first_frame));
3310     if(tng_data->output_endianness_swap_func_64)
3311     {
3312         if(tng_data->output_endianness_swap_func_64(tng_data,
3313                                       (int64_t *)block->header_contents+offset)
3314             != TNG_SUCCESS)
3315         {
3316             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3317                     __FILE__, __LINE__);
3318         }
3319     }
3320     offset += sizeof(frame_set->first_frame);
3321
3322     memcpy(block->block_contents+offset, &frame_set->n_frames,
3323            sizeof(frame_set->n_frames));
3324     if(tng_data->output_endianness_swap_func_64)
3325     {
3326         if(tng_data->output_endianness_swap_func_64(tng_data,
3327                                       (int64_t *)block->header_contents+offset)
3328             != TNG_SUCCESS)
3329         {
3330             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3331                     __FILE__, __LINE__);
3332         }
3333     }
3334     offset += sizeof(frame_set->n_frames);
3335
3336     if(tng_data->var_num_atoms_flag)
3337     {
3338         for(i = 0; i < tng_data->n_molecules; i++)
3339         {
3340             memcpy(block->block_contents+offset,
3341                    &frame_set->molecule_cnt_list[i],
3342                    sizeof(int64_t));
3343             if(tng_data->output_endianness_swap_func_64)
3344             {
3345                 if(tng_data->output_endianness_swap_func_64(tng_data,
3346                                             (int64_t *)block->header_contents+offset)
3347                     != TNG_SUCCESS)
3348                 {
3349                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3350                             __FILE__, __LINE__);
3351                 }
3352             }
3353             offset += sizeof(int64_t);
3354         }
3355     }
3356
3357
3358     memcpy(block->block_contents+offset, &frame_set->next_frame_set_file_pos,
3359            sizeof(frame_set->next_frame_set_file_pos));
3360     if(tng_data->output_endianness_swap_func_64)
3361     {
3362         if(tng_data->output_endianness_swap_func_64(tng_data,
3363                                       (int64_t *)block->header_contents+offset)
3364             != TNG_SUCCESS)
3365         {
3366             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3367                     __FILE__, __LINE__);
3368         }
3369     }
3370     offset += sizeof(frame_set->next_frame_set_file_pos);
3371
3372     memcpy(block->block_contents+offset, &frame_set->prev_frame_set_file_pos,
3373            sizeof(frame_set->prev_frame_set_file_pos));
3374     if(tng_data->output_endianness_swap_func_64)
3375     {
3376         if(tng_data->output_endianness_swap_func_64(tng_data,
3377                                       (int64_t *)block->header_contents+offset)
3378             != TNG_SUCCESS)
3379         {
3380             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3381                     __FILE__, __LINE__);
3382         }
3383     }
3384     offset += sizeof(frame_set->prev_frame_set_file_pos);
3385
3386     memcpy(block->block_contents+offset,
3387            &frame_set->medium_stride_next_frame_set_file_pos,
3388            sizeof(frame_set->medium_stride_next_frame_set_file_pos));
3389     if(tng_data->output_endianness_swap_func_64)
3390     {
3391         if(tng_data->output_endianness_swap_func_64(tng_data,
3392                                       (int64_t *)block->header_contents+offset)
3393             != TNG_SUCCESS)
3394         {
3395             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3396                     __FILE__, __LINE__);
3397         }
3398     }
3399     offset += sizeof(frame_set->medium_stride_next_frame_set_file_pos);
3400
3401     memcpy(block->block_contents+offset,
3402            &frame_set->medium_stride_prev_frame_set_file_pos,
3403            sizeof(frame_set->medium_stride_prev_frame_set_file_pos));
3404     if(tng_data->output_endianness_swap_func_64)
3405     {
3406         if(tng_data->output_endianness_swap_func_64(tng_data,
3407                                       (int64_t *)block->header_contents+offset)
3408             != TNG_SUCCESS)
3409         {
3410             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3411                     __FILE__, __LINE__);
3412         }
3413     }
3414     offset += sizeof(frame_set->medium_stride_prev_frame_set_file_pos);
3415
3416     memcpy(block->block_contents+offset,
3417            &frame_set->long_stride_next_frame_set_file_pos,
3418            sizeof(frame_set->long_stride_next_frame_set_file_pos));
3419     if(tng_data->output_endianness_swap_func_64)
3420     {
3421         if(tng_data->output_endianness_swap_func_64(tng_data,
3422                                       (int64_t *)block->header_contents+offset)
3423             != TNG_SUCCESS)
3424         {
3425             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3426                     __FILE__, __LINE__);
3427         }
3428     }
3429     offset += sizeof(frame_set->long_stride_next_frame_set_file_pos);
3430
3431     memcpy(block->block_contents+offset,
3432            &frame_set->long_stride_prev_frame_set_file_pos,
3433            sizeof(frame_set->long_stride_prev_frame_set_file_pos));
3434     if(tng_data->output_endianness_swap_func_64)
3435     {
3436         if(tng_data->output_endianness_swap_func_64(tng_data,
3437                                       (int64_t *)block->header_contents+offset)
3438             != TNG_SUCCESS)
3439         {
3440             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3441                     __FILE__, __LINE__);
3442         }
3443     }
3444     offset += sizeof(frame_set->long_stride_prev_frame_set_file_pos);
3445
3446     memcpy(block->block_contents+offset,
3447            &frame_set->first_frame_time,
3448            sizeof(frame_set->first_frame_time));
3449     if(tng_data->output_endianness_swap_func_64)
3450     {
3451         if(tng_data->output_endianness_swap_func_64(tng_data,
3452                                       (int64_t *)block->header_contents+offset)
3453             != TNG_SUCCESS)
3454         {
3455             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3456                     __FILE__, __LINE__);
3457         }
3458     }
3459     offset += sizeof(frame_set->first_frame_time);
3460
3461     memcpy(block->block_contents+offset,
3462            &tng_data->time_per_frame,
3463            sizeof(tng_data->time_per_frame));
3464     if(tng_data->output_endianness_swap_func_64)
3465     {
3466         if(tng_data->output_endianness_swap_func_64(tng_data,
3467                                       (int64_t *)block->header_contents+offset)
3468             != TNG_SUCCESS)
3469         {
3470             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3471                     __FILE__, __LINE__);
3472         }
3473     }
3474
3475     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
3476     {
3477         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
3478                tng_data->output_file_path, __FILE__, __LINE__);
3479         return(TNG_CRITICAL);
3480     }
3481
3482     if(fwrite(block->block_contents, block->block_contents_size, 1,
3483               tng_data->output_file) != 1)
3484     {
3485         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__, __LINE__);
3486         return(TNG_CRITICAL);
3487     }
3488
3489     return(TNG_SUCCESS);
3490 }
3491
3492
3493 /** Read an atom mappings block (translating between real atom indexes and how
3494  *  the atom info is written in this frame set).
3495  * @param tng_data is a trajectory data container.
3496  * @param block is a general block container.
3497  * @param hash_mode is an option to decide whether to use the md5 hash or not.
3498  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
3499  * compared to the md5 hash of the read contents to ensure valid data.
3500  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3501  * error has occured.
3502  */
3503 static tng_function_status tng_trajectory_mapping_block_read
3504                 (tng_trajectory_t tng_data,
3505                  tng_gen_block_t block,
3506                  const char hash_mode)
3507 {
3508     int64_t i;
3509     int offset = 0;
3510     tng_bool same_hash;
3511     tng_trajectory_frame_set_t frame_set =
3512     &tng_data->current_trajectory_frame_set;
3513
3514     tng_particle_mapping_t mapping, mappings;
3515
3516     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
3517     {
3518         return(TNG_CRITICAL);
3519     }
3520
3521     if(block->block_contents)
3522     {
3523         free(block->block_contents);
3524     }
3525
3526     block->block_contents = malloc(block->block_contents_size);
3527     if(!block->block_contents)
3528     {
3529         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3530                block->block_contents_size, __FILE__, __LINE__);
3531         return(TNG_CRITICAL);
3532     }
3533
3534     /* Read the whole block into block_contents to be able to write it to disk
3535      *  even if it cannot be interpreted. */
3536     if(fread(block->block_contents, block->block_contents_size, 1,
3537         tng_data->input_file) == 0)
3538     {
3539         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
3540         return(TNG_CRITICAL);
3541     }
3542
3543     /* FIXME: Does not check if the size of the contents matches the expected
3544      * size or if the contents can be read. */
3545
3546     if(hash_mode == TNG_USE_HASH)
3547     {
3548         tng_md5_hash_match_verify(block, &same_hash);
3549         if(same_hash != TNG_TRUE)
3550         {
3551             fprintf(stderr, "TNG library: Particle mapping block contents corrupt. Hashes do not match. "
3552                 "%s: %d\n",
3553                 __FILE__, __LINE__);
3554     /*         return(TNG_FAILURE); */
3555         }
3556     }
3557
3558     frame_set->n_mapping_blocks++;
3559     mappings = realloc(frame_set->mappings,
3560                        sizeof(struct tng_particle_mapping) *
3561                        frame_set->n_mapping_blocks);
3562     if(!mappings)
3563     {
3564         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3565                block->block_contents_size, __FILE__, __LINE__);
3566         free(frame_set->mappings);
3567         frame_set->mappings = 0;
3568         return(TNG_CRITICAL);
3569     }
3570     frame_set->mappings = mappings;
3571     mapping = &mappings[frame_set->n_mapping_blocks - 1];
3572
3573
3574     memcpy(&mapping->num_first_particle, block->block_contents+offset,
3575            sizeof(mapping->num_first_particle));
3576     if(tng_data->input_endianness_swap_func_64)
3577     {
3578         if(tng_data->input_endianness_swap_func_64(tng_data,
3579                                                    &mapping->num_first_particle)
3580             != TNG_SUCCESS)
3581         {
3582             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3583                     __FILE__, __LINE__);
3584         }
3585     }
3586     offset += sizeof(mapping->num_first_particle);
3587
3588     memcpy(&mapping->n_particles, block->block_contents+offset,
3589            sizeof(mapping->n_particles));
3590     if(tng_data->input_endianness_swap_func_64)
3591     {
3592         if(tng_data->input_endianness_swap_func_64(tng_data,
3593                                                    &mapping->n_particles)
3594             != TNG_SUCCESS)
3595         {
3596             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3597                     __FILE__, __LINE__);
3598         }
3599     }
3600     offset += sizeof(mapping->n_particles);
3601
3602     mapping->real_particle_numbers = malloc(mapping->n_particles *
3603                                             sizeof(int64_t));
3604     if(!mapping->real_particle_numbers)
3605     {
3606         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3607                 mapping->n_particles * sizeof(int64_t), __FILE__, __LINE__);
3608         return(TNG_CRITICAL);
3609     }
3610
3611     /* If the byte order needs to be swapped the data must be read one value at
3612      * a time and swapped */
3613     if(tng_data->input_endianness_swap_func_64)
3614     {
3615         for(i = 0; i < mapping->n_particles; i++)
3616         {
3617             memcpy(&mapping->real_particle_numbers[i],
3618                     block->block_contents + offset,
3619                     sizeof(int64_t));
3620             if(tng_data->input_endianness_swap_func_64(tng_data,
3621                                             &mapping->real_particle_numbers[i])
3622                 != TNG_SUCCESS)
3623             {
3624                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3625                         __FILE__, __LINE__);
3626             }
3627             offset += sizeof(int64_t);
3628         }
3629     }
3630     /* Otherwise the data can be read all at once */
3631     else
3632     {
3633         memcpy(mapping->real_particle_numbers, block->block_contents + offset,
3634                mapping->n_particles * sizeof(int64_t));
3635     }
3636
3637
3638     return(TNG_SUCCESS);
3639 }
3640
3641 /** Write the atom mappings of the current trajectory frame set
3642  * @param tng_data is a trajectory data container.
3643  * @param block is a general block container.
3644  * @param mapping_block_nr is the index of the mapping block to write.
3645  * @param hash_mode is an option to decide whether to use the md5 hash or not.
3646  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
3647  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
3648  * has occurred or TNG_CRITICAL (2) if a major error has occured.
3649  */
3650 static tng_function_status tng_trajectory_mapping_block_write
3651                 (tng_trajectory_t tng_data,
3652                  tng_gen_block_t block,
3653                  int mapping_block_nr,
3654                  const char hash_mode)
3655 {
3656     char *temp_name;
3657     int i, offset = 0;
3658     unsigned int name_len;
3659     tng_particle_mapping_t mapping =
3660     &tng_data->current_trajectory_frame_set.mappings[mapping_block_nr];
3661
3662     if(mapping_block_nr >=
3663        tng_data->current_trajectory_frame_set.n_mapping_blocks)
3664     {
3665         fprintf(stderr, "TNG library: Mapping block index out of bounds. %s: %d\n",
3666                __FILE__, __LINE__);
3667         return(TNG_FAILURE);
3668     }
3669
3670     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
3671     {
3672         return(TNG_CRITICAL);
3673     }
3674
3675     name_len = (int)strlen("PARTICLE MAPPING");
3676
3677     if(!block->name || strlen(block->name) < name_len)
3678     {
3679         temp_name = realloc(block->name, name_len + 1);
3680         if(!temp_name)
3681         {
3682             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
3683                    name_len+1, __FILE__, __LINE__);
3684             free(block->name);
3685             block->name = 0;
3686             return(TNG_CRITICAL);
3687         }
3688         block->name = temp_name;
3689     }
3690     strcpy(block->name, "PARTICLE MAPPING");
3691     block->id = TNG_PARTICLE_MAPPING;
3692
3693     block->block_contents_size = sizeof(int64_t) * (2 + mapping->n_particles);
3694
3695     if(block->block_contents)
3696     {
3697         free(block->block_contents);
3698     }
3699     block->block_contents = malloc(block->block_contents_size);
3700     if(!block->block_contents)
3701     {
3702         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3703                block->block_contents_size, __FILE__, __LINE__);
3704         return(TNG_CRITICAL);
3705     }
3706
3707     memcpy(block->block_contents, &mapping->num_first_particle,
3708            sizeof(mapping->num_first_particle));
3709     if(tng_data->output_endianness_swap_func_64)
3710     {
3711         if(tng_data->output_endianness_swap_func_64(tng_data,
3712                                       (int64_t *)block->header_contents+offset)
3713             != TNG_SUCCESS)
3714         {
3715             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3716                     __FILE__, __LINE__);
3717         }
3718     }
3719     offset += sizeof(mapping->num_first_particle);
3720
3721     memcpy(block->block_contents+offset, &mapping->n_particles,
3722            sizeof(mapping->n_particles));
3723     if(tng_data->output_endianness_swap_func_64)
3724     {
3725         if(tng_data->output_endianness_swap_func_64(tng_data,
3726                                       (int64_t *)block->header_contents+offset)
3727             != TNG_SUCCESS)
3728         {
3729             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3730                     __FILE__, __LINE__);
3731         }
3732     }
3733     offset += sizeof(mapping->n_particles);
3734
3735     if(tng_data->output_endianness_swap_func_64)
3736     {
3737         for(i = 0; i < mapping->n_particles; i++)
3738         {
3739             memcpy(block->block_contents+offset, &mapping->real_particle_numbers[i],
3740                 sizeof(int64_t));
3741             if(tng_data->output_endianness_swap_func_64(tng_data,
3742                                         (int64_t *)block->header_contents+offset)
3743                 != TNG_SUCCESS)
3744             {
3745                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3746                         __FILE__, __LINE__);
3747             }
3748             offset += sizeof(int64_t);
3749         }
3750     }
3751     else
3752     {
3753         memcpy(block->block_contents+offset, mapping->real_particle_numbers,
3754                mapping->n_particles * sizeof(int64_t));
3755     }
3756
3757
3758     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
3759     {
3760         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
3761                tng_data->output_file_path, __FILE__, __LINE__);
3762         return(TNG_CRITICAL);
3763     }
3764
3765     if(fwrite(block->block_contents, block->block_contents_size, 1,
3766               tng_data->output_file) != 1)
3767     {
3768         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__, __LINE__);
3769         return(TNG_CRITICAL);
3770     }
3771
3772     return(TNG_SUCCESS);
3773 }
3774
3775 /** Prepare a block for storing particle data
3776  * @param tng_data is a trajectory data container.
3777  * @param block_type_flag specifies if this is a trajectory block or a
3778  * non-trajectory block. (TNG_TRAJECTORY_BLOCK or TNG_NON_TRAJECTORY_BLOCK)
3779  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3780  * error has occured.
3781  */
3782 static tng_function_status tng_particle_data_block_create
3783                 (tng_trajectory_t tng_data,
3784                  const char block_type_flag)
3785 {
3786     tng_trajectory_frame_set_t frame_set =
3787     &tng_data->current_trajectory_frame_set;
3788
3789     tng_particle_data_t data;
3790
3791     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
3792     {
3793         frame_set->n_particle_data_blocks++;
3794         data = realloc(frame_set->tr_particle_data,
3795                     sizeof(struct tng_particle_data) *
3796                     frame_set->n_particle_data_blocks);
3797         if(!data)
3798         {
3799             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
3800                 sizeof(struct tng_particle_data) *
3801                 frame_set->n_particle_data_blocks,
3802                 __FILE__, __LINE__);
3803             free(frame_set->tr_particle_data);
3804             frame_set->tr_particle_data = 0;
3805             return(TNG_CRITICAL);
3806         }
3807         frame_set->tr_particle_data = data;
3808     }
3809     else
3810     {
3811         tng_data->n_particle_data_blocks++;
3812         data = realloc(tng_data->non_tr_particle_data,
3813                         sizeof(struct tng_particle_data) *
3814                         tng_data->n_particle_data_blocks);
3815         if(!data)
3816         {
3817             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
3818                     sizeof(struct tng_particle_data) *
3819                     tng_data->n_particle_data_blocks,
3820                     __FILE__, __LINE__);
3821             free(tng_data->non_tr_particle_data);
3822             tng_data->non_tr_particle_data = 0;
3823             return(TNG_CRITICAL);
3824         }
3825         tng_data->non_tr_particle_data = data;
3826     }
3827
3828     return(TNG_SUCCESS);
3829 }
3830
3831 static tng_function_status tng_compress(tng_trajectory_t tng_data,
3832                                         tng_gen_block_t block,
3833                                         const int64_t n_frames,
3834                                         const int64_t n_particles,
3835                                         const char type,
3836                                         void *start_pos)
3837 {
3838     int nalgo;
3839     int new_len;
3840     int *alt_algo = 0;
3841     char *dest, *temp;
3842     int64_t algo_find_n_frames;
3843     unsigned long offset;
3844     float f_precision;
3845     double d_precision;
3846
3847     if(block->id != TNG_TRAJ_POSITIONS &&
3848        block->id != TNG_TRAJ_VELOCITIES)
3849     {
3850         fprintf(stderr, "TNG library: Can only compress positions and velocities with the "
3851                "TNG method. %s: %d\n", __FILE__, __LINE__);
3852         return(TNG_FAILURE);
3853     }
3854     if(type != TNG_FLOAT_DATA && type != TNG_DOUBLE_DATA)
3855     {
3856         fprintf(stderr, "TNG library: Data type not supported. %s: %d\n", __FILE__, __LINE__);
3857         return(TNG_FAILURE);
3858     }
3859
3860     if(n_frames <= 0 || n_particles <= 0)
3861     {
3862         fprintf(stderr, "TNG library: Missing frames or particles. Cannot compress data "
3863                "with the TNG method. %s: %d\n", __FILE__, __LINE__);
3864         return(TNG_FAILURE);
3865     }
3866
3867     f_precision = 1/(float)tng_data->compression_precision;
3868     d_precision = 1/tng_data->compression_precision;
3869
3870     if(block->id == TNG_TRAJ_POSITIONS)
3871     {
3872         /* If there is only one frame in this frame set and there might be more
3873          * do not store the algorithm as the compression algorithm, but find
3874          * the best one without storing it */
3875         if(n_frames == 1 && tng_data->frame_set_n_frames > 1)
3876         {
3877             nalgo = tng_compress_nalgo();
3878             alt_algo=malloc(nalgo * sizeof *tng_data->compress_algo_pos);
3879             if(type == TNG_FLOAT_DATA)
3880             {
3881                 dest = tng_compress_pos_float_find_algo(start_pos, (int)n_particles,
3882                                                         (int)n_frames,
3883                                                         f_precision,
3884                                                         0, alt_algo,
3885                                                         &new_len);
3886
3887             }
3888             else
3889             {
3890                 dest = tng_compress_pos_find_algo(start_pos, (int)n_particles,
3891                                            (int)n_frames,
3892                                            d_precision,
3893                                            0, alt_algo,
3894                                            &new_len);
3895             }
3896         }
3897         else if(!tng_data->compress_algo_pos)
3898         {
3899             if(n_frames > 10)
3900             {
3901                 algo_find_n_frames = 5;
3902             }
3903             else
3904             {
3905                 algo_find_n_frames = n_frames;
3906             }
3907
3908             nalgo = tng_compress_nalgo();
3909             tng_data->compress_algo_pos=malloc(nalgo *
3910                                            sizeof *tng_data->compress_algo_pos);
3911             if(type == TNG_FLOAT_DATA)
3912             {
3913                 dest = tng_compress_pos_float_find_algo(start_pos, (int)n_particles,
3914                                                         (int)algo_find_n_frames,
3915                                                         f_precision,
3916                                                         0, tng_data->
3917                                                         compress_algo_pos,
3918                                                         &new_len);
3919
3920                 if(algo_find_n_frames < n_frames)
3921                 {
3922                     dest = tng_compress_pos_float(start_pos, (int)n_particles,
3923                                                   (int)n_frames,
3924                                                   f_precision,
3925                                                   0, tng_data->compress_algo_pos,
3926                                                   &new_len);
3927                 }
3928             }
3929             else
3930             {
3931                 dest = tng_compress_pos_find_algo(start_pos, (int)n_particles,
3932                                            (int)algo_find_n_frames,
3933                                            d_precision,
3934                                            0, tng_data->
3935                                            compress_algo_pos,
3936                                            &new_len);
3937
3938                 if(algo_find_n_frames < n_frames)
3939                 {
3940                     dest = tng_compress_pos(start_pos, (int)n_particles,
3941                                             (int)n_frames,
3942                                             d_precision, 0,
3943                                             tng_data->compress_algo_pos,
3944                                             &new_len);
3945                 }
3946             }
3947         }
3948         else
3949         {
3950             if(type == TNG_FLOAT_DATA)
3951             {
3952                 dest = tng_compress_pos_float(start_pos, (int)n_particles,
3953                                               (int)n_frames,
3954                                               f_precision, 0,
3955                                               tng_data->compress_algo_pos, &new_len);
3956             }
3957             else
3958             {
3959                 dest = tng_compress_pos(start_pos, (int)n_particles,
3960                                         (int)n_frames,
3961                                         d_precision, 0,
3962                                         tng_data->compress_algo_pos,
3963                                         &new_len);
3964             }
3965         }
3966     }
3967     else if(block->id == TNG_TRAJ_VELOCITIES)
3968     {
3969         /* If there is only one frame in this frame set and there might be more
3970          * do not store the algorithm as the compression algorithm, but find
3971          * the best one without storing it */
3972         if(n_frames == 1 && tng_data->frame_set_n_frames > 1)
3973         {
3974             nalgo = tng_compress_nalgo();
3975             alt_algo=malloc(nalgo * sizeof *tng_data->compress_algo_pos);
3976             if(type == TNG_FLOAT_DATA)
3977             {
3978                 dest = tng_compress_vel_float_find_algo(start_pos, (int)n_particles,
3979                                                         (int)n_frames,
3980                                                         f_precision,
3981                                                         0, alt_algo,
3982                                                         &new_len);
3983
3984             }
3985             else
3986             {
3987                 dest = tng_compress_vel_find_algo(start_pos, (int)n_particles,
3988                                                   (int)n_frames,
3989                                                   d_precision,
3990                                                   0, alt_algo,
3991                                                   &new_len);
3992             }
3993         }
3994         else if(!tng_data->compress_algo_vel)
3995         {
3996             if(n_frames > 10)
3997             {
3998                 algo_find_n_frames = 5;
3999             }
4000             else
4001             {
4002                 algo_find_n_frames = n_frames;
4003             }
4004
4005             nalgo = tng_compress_nalgo();
4006             tng_data->compress_algo_vel=malloc(nalgo *
4007                                            sizeof *tng_data->compress_algo_vel);
4008
4009             if(type == TNG_FLOAT_DATA)
4010             {
4011                 dest = tng_compress_vel_float_find_algo(start_pos, (int)n_particles,
4012                                                         (int)algo_find_n_frames,
4013                                                         f_precision,
4014                                                         0, tng_data->
4015                                                         compress_algo_vel,
4016                                                         &new_len);
4017                 if(algo_find_n_frames < n_frames)
4018                 {
4019                     dest = tng_compress_vel_float(start_pos, (int)n_particles,
4020                                                   (int)n_frames,
4021                                                   f_precision,
4022                                                   0, tng_data->compress_algo_vel,
4023                                                   &new_len);
4024                 }
4025             }
4026             else
4027             {
4028                 dest = tng_compress_vel_find_algo(start_pos, (int)n_particles,
4029                                                   (int)algo_find_n_frames,
4030                                                   d_precision,
4031                                                   0, tng_data->
4032                                                   compress_algo_vel,
4033                                                   &new_len);
4034                 if(algo_find_n_frames < n_frames)
4035                 {
4036                     dest = tng_compress_vel(start_pos, (int)n_particles,
4037                                             (int)n_frames,
4038                                             d_precision,
4039                                             0, tng_data->compress_algo_vel,
4040                                             &new_len);
4041                 }
4042             }
4043         }
4044         else
4045         {
4046             if(type == TNG_FLOAT_DATA)
4047             {
4048                 dest = tng_compress_vel_float(start_pos, (int)n_particles,
4049                                               (int)n_frames,
4050                                               f_precision,
4051                                               0, tng_data->
4052                                               compress_algo_vel,
4053                                               &new_len);
4054             }
4055             else
4056             {
4057                 dest = tng_compress_vel(start_pos, (int)n_particles,
4058                                         (int)n_frames,
4059                                         d_precision,
4060                                         0, tng_data->
4061                                         compress_algo_vel,
4062                                         &new_len);
4063             }
4064         }
4065     }
4066     else
4067     {
4068         fprintf(stderr, "TNG library: Can only compress positions and velocities using TNG-MF1 algorithms.\n");
4069         return(TNG_FAILURE);
4070     }
4071
4072     offset = (unsigned long)((char *)start_pos - block->block_contents);
4073
4074     if(alt_algo)
4075     {
4076         free(alt_algo);
4077     }
4078
4079     block->block_contents_size = new_len + offset;
4080
4081     temp = realloc(block->block_contents, block->block_contents_size);
4082     if(!temp)
4083     {
4084         free(block->block_contents);
4085         block->block_contents = 0;
4086         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4087                block->block_contents_size, __FILE__, __LINE__);
4088         return(TNG_CRITICAL);
4089     }
4090     block->block_contents = temp;
4091     if(dest)
4092     {
4093         memcpy(temp + offset, dest, new_len);
4094         free(dest);
4095     }
4096     else
4097     {
4098         fprintf(stderr, "TNG library: Error during TNG compression. %s: %d\n", __FILE__, __LINE__);
4099         return(TNG_FAILURE);
4100     }
4101
4102     return(TNG_SUCCESS);
4103 }
4104
4105 static tng_function_status tng_uncompress(tng_trajectory_t tng_data,
4106                                           tng_gen_block_t block,
4107                                           const char type,
4108                                           void *start_pos,
4109                                           const unsigned long uncompressed_len)
4110 {
4111     char *temp;
4112     double *d_dest = 0;
4113     float *f_dest = 0;
4114     unsigned long offset;
4115     int result;
4116     (void)tng_data;
4117
4118     TNG_ASSERT(uncompressed_len, "TNG library: The full length of the uncompressed data must be > 0.");
4119
4120     if(block->id != TNG_TRAJ_POSITIONS &&
4121        block->id != TNG_TRAJ_VELOCITIES)
4122     {
4123         fprintf(stderr, "TNG library: Can only uncompress positions and velocities with the"
4124                "TNG method.\n");
4125         return(TNG_FAILURE);
4126     }
4127     if(type != TNG_FLOAT_DATA && type != TNG_DOUBLE_DATA)
4128     {
4129         fprintf(stderr, "TNG library: Data type not supported.\n");
4130         return(TNG_FAILURE);
4131     }
4132
4133     if(type == TNG_FLOAT_DATA)
4134     {
4135         f_dest = malloc(uncompressed_len);
4136         if(!f_dest)
4137         {
4138             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
4139                 uncompressed_len, __FILE__, __LINE__);
4140             return(TNG_CRITICAL);
4141         }
4142         result = tng_compress_uncompress_float(start_pos, f_dest);
4143     }
4144     else
4145     {
4146         d_dest = malloc(uncompressed_len);
4147         if(!d_dest)
4148         {
4149             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
4150                 uncompressed_len, __FILE__, __LINE__);
4151             return(TNG_CRITICAL);
4152         }
4153         result = tng_compress_uncompress(start_pos, d_dest);
4154     }
4155
4156     if(result == 1)
4157     {
4158         fprintf(stderr, "TNG library: Cannot uncompress TNG compressed block.\n");
4159         return(TNG_FAILURE);
4160     }
4161
4162     offset = (unsigned long)((char *)start_pos - (char *)block->block_contents);
4163
4164     block->block_contents_size = (int64_t)(uncompressed_len + offset);
4165
4166     temp = realloc(block->block_contents, uncompressed_len + offset);
4167     if(!temp)
4168     {
4169         free(block->block_contents);
4170         block->block_contents = 0;
4171         if(d_dest)
4172         {
4173             free(d_dest);
4174         }
4175         if(f_dest)
4176         {
4177             free(f_dest);
4178         }
4179         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4180                block->block_contents_size, __FILE__, __LINE__);
4181         return(TNG_CRITICAL);
4182     }
4183
4184     if(type == TNG_FLOAT_DATA)
4185     {
4186         memcpy(temp + offset, f_dest, uncompressed_len);
4187     }
4188     else
4189     {
4190         memcpy(temp + offset, d_dest, uncompressed_len);
4191     }
4192
4193     block->block_contents = temp;
4194
4195     if(d_dest)
4196     {
4197         free(d_dest);
4198     }
4199     if(f_dest)
4200     {
4201         free(f_dest);
4202     }
4203     return(TNG_SUCCESS);
4204 }
4205
4206 #ifdef USE_ZLIB
4207 static tng_function_status tng_gzip_compress(tng_trajectory_t tng_data,
4208                                              tng_gen_block_t block,
4209                                              void *start_pos, const int len)
4210 {
4211     Bytef *dest;
4212     char *temp;
4213     unsigned long max_len, stat, offset;
4214     (void)tng_data;
4215
4216     max_len = compressBound(len);
4217     dest = malloc(max_len);
4218     if(!dest)
4219     {
4220         fprintf(stderr, "TNG library: Cannot allocate memory (%ld bytes). %s: %d\n",
4221                max_len, __FILE__, __LINE__);
4222         return(TNG_CRITICAL);
4223     }
4224
4225     stat = compress(dest, &max_len, start_pos, len);
4226     if(stat != (unsigned long)Z_OK)
4227     {
4228         free(dest);
4229         if(stat == (unsigned long)Z_MEM_ERROR)
4230         {
4231             fprintf(stderr, "TNG library: Not enough memory. ");
4232         }
4233         else if(stat == (unsigned long)Z_BUF_ERROR)
4234         {
4235             fprintf(stderr, "TNG library: Destination buffer too small. ");
4236         }
4237         fprintf(stderr, "TNG library: Error gzipping data. %s: %d\n", __FILE__, __LINE__);
4238         return(TNG_FAILURE);
4239     }
4240
4241     offset = (char *)start_pos - block->block_contents;
4242
4243     block->block_contents_size = max_len + offset;
4244
4245     temp = realloc(block->block_contents, block->block_contents_size);
4246     if(!temp)
4247     {
4248         free(block->block_contents);
4249         free(dest);
4250         block->block_contents = 0;
4251         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4252                block->block_contents_size, __FILE__, __LINE__);
4253         return(TNG_CRITICAL);
4254     }
4255
4256     block->block_contents = temp;
4257
4258     memcpy(temp + offset, dest, max_len);
4259
4260     free(dest);
4261
4262     return(TNG_SUCCESS);
4263 }
4264
4265 static tng_function_status tng_gzip_uncompress(tng_trajectory_t tng_data,
4266                                                tng_gen_block_t block,
4267                                                void *start_pos,
4268                                                unsigned long uncompressed_len)
4269 {
4270     Bytef *dest;
4271     char *temp;
4272     unsigned long stat;
4273     int offset;
4274     (void)tng_data;
4275
4276     offset = (char *)start_pos - (char *)block->block_contents;
4277
4278     dest = malloc(uncompressed_len);
4279     if(!dest)
4280     {
4281         fprintf(stderr, "TNG library: Cannot allocate memory (%lud bytes). %s: %d\n",
4282                uncompressed_len, __FILE__, __LINE__);
4283         return(TNG_CRITICAL);
4284     }
4285
4286     stat = uncompress(dest, &uncompressed_len, (Bytef *) start_pos,
4287                       block->block_contents_size - offset);
4288
4289     if(stat != Z_OK)
4290     {
4291         free(dest);
4292         if(stat == (unsigned long)Z_MEM_ERROR)
4293         {
4294             fprintf(stderr, "TNG library: Not enough memory. ");
4295         }
4296         else if(stat == (unsigned long)Z_BUF_ERROR)
4297         {
4298             fprintf(stderr, "TNG library: Destination buffer too small. ");
4299         }
4300         else if(stat == (unsigned long)Z_DATA_ERROR)
4301         {
4302             fprintf(stderr, "TNG library: Data corrupt. ");
4303         }
4304         fprintf(stderr, "TNG library: Error uncompressing gzipped data. %s: %d\n", __FILE__,
4305                __LINE__);
4306         return(TNG_FAILURE);
4307     }
4308
4309
4310     block->block_contents_size = uncompressed_len + offset;
4311
4312     temp = realloc(block->block_contents, uncompressed_len + offset);
4313     if(!temp)
4314     {
4315         free(block->block_contents);
4316         block->block_contents = 0;
4317         free(dest);
4318         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4319                block->block_contents_size, __FILE__, __LINE__);
4320         return(TNG_CRITICAL);
4321     }
4322
4323     memcpy(temp + offset, dest, uncompressed_len);
4324
4325     block->block_contents = temp;
4326
4327     free(dest);
4328     return(TNG_SUCCESS);
4329 }
4330 #endif
4331
4332 /** Allocate memory for storing particle data.
4333  * The allocated block will be refered to by data->values.
4334  * @param tng_data is a trajectory data container.
4335  * @param data is the data struct, which will contain the allocated memory in
4336  * data->values.
4337  * @param n_frames is the number of frames of data to store.
4338  * @param n_particles is the number of particles with data.
4339  * @param n_values_per_frame is the number of data values per particle and
4340  * frame.
4341  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
4342  * error has occured.
4343  */
4344 static tng_function_status tng_allocate_particle_data_mem
4345                 (tng_trajectory_t tng_data,
4346                  tng_particle_data_t data,
4347                  int64_t n_frames,
4348                  int64_t stride_length,
4349                  const int64_t n_particles,
4350                  const int64_t n_values_per_frame)
4351 {
4352     void ***values;
4353     int64_t i, j, k, size, frame_alloc;
4354     (void)tng_data;
4355
4356     if(n_particles == 0 || n_values_per_frame == 0)
4357     {
4358         return(TNG_FAILURE);
4359     }
4360
4361     if(data->strings && data->datatype == TNG_CHAR_DATA)
4362     {
4363         for(i = data->n_frames; i--;)
4364         {
4365             for(j = n_particles; j--;)
4366             {
4367                 for(k = data->n_values_per_frame; k--;)
4368                 {
4369                     if(data->strings[i][j][k])
4370                     {
4371                         free(data->strings[i][j][k]);
4372                     }
4373                 }
4374                 free(data->strings[i][j]);
4375             }
4376             free(data->strings[i]);
4377         }
4378         free(data->strings);
4379     }
4380     data->n_frames = n_frames;
4381     n_frames = tng_max_i64(1, n_frames);
4382     data->stride_length = tng_max_i64(1, stride_length);
4383     data->n_values_per_frame = n_values_per_frame;
4384     frame_alloc = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
4385
4386     if(data->datatype == TNG_CHAR_DATA)
4387     {
4388         data->strings = malloc(sizeof(char ***) * frame_alloc);
4389         for(i = frame_alloc; i-- ;)
4390         {
4391             data->strings[i] = malloc(sizeof(char **) *
4392                                     n_particles);
4393             if(!data->strings[i])
4394             {
4395                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4396                     sizeof(union data_values *) * n_particles,
4397                     __FILE__, __LINE__);
4398                 return(TNG_CRITICAL);
4399             }
4400             for(j = n_particles; j--;)
4401             {
4402                 data->strings[i][j] = malloc(sizeof(char *) *
4403                                             n_values_per_frame);
4404                 if(!data->strings[i][j])
4405                 {
4406                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4407                         sizeof(union data_values) * n_values_per_frame,
4408                         __FILE__, __LINE__);
4409                     return(TNG_CRITICAL);
4410                 }
4411                 for(k = n_values_per_frame; k--;)
4412                 {
4413                     data->strings[i][j][k] = 0;
4414                 }
4415             }
4416         }
4417     }
4418     else
4419     {
4420         switch(data->datatype)
4421         {
4422         case TNG_INT_DATA:
4423             size = sizeof(int64_t);
4424             break;
4425         case TNG_FLOAT_DATA:
4426             size = sizeof(float);
4427             break;
4428         case TNG_DOUBLE_DATA:
4429         default:
4430             size = sizeof(double);
4431         }
4432
4433         values = realloc(data->values,
4434                          size * frame_alloc *
4435                          n_particles * n_values_per_frame);
4436         if(!values)
4437         {
4438             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4439                    size * frame_alloc *
4440                    n_particles * n_values_per_frame,
4441                    __FILE__, __LINE__);
4442             free(data->values);
4443             data->values = 0;
4444             return(TNG_CRITICAL);
4445         }
4446         data->values = values;
4447     }
4448     return(TNG_SUCCESS);
4449 }
4450
4451 static tng_function_status tng_particle_data_find
4452                 (tng_trajectory_t tng_data,
4453                  const int64_t id,
4454                  tng_particle_data_t *data)
4455 {
4456     int64_t block_index, i;
4457     tng_trajectory_frame_set_t frame_set = &tng_data->
4458                                            current_trajectory_frame_set;
4459     char block_type_flag;
4460
4461     if(tng_data->current_trajectory_frame_set_input_file_pos > 0 ||
4462        tng_data->current_trajectory_frame_set_output_file_pos > 0)
4463     {
4464         block_type_flag = TNG_TRAJECTORY_BLOCK;
4465     }
4466     else
4467     {
4468         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
4469     }
4470
4471     block_index = -1;
4472     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
4473     {
4474         for(i = frame_set->n_particle_data_blocks; i-- ;)
4475         {
4476             *data = &frame_set->tr_particle_data[i];
4477             if((*data)->block_id == id)
4478             {
4479                 block_index = i;
4480                 break;
4481             }
4482         }
4483     }
4484     else
4485     {
4486         for(i = tng_data->n_particle_data_blocks; i-- ;)
4487         {
4488             *data = &tng_data->non_tr_particle_data[i];
4489             if((*data)->block_id == id)
4490             {
4491                 block_index = i;
4492                 break;
4493             }
4494         }
4495     }
4496     if(block_index == -1)
4497     {
4498         return(TNG_FAILURE);
4499     }
4500     return(TNG_SUCCESS);
4501 }
4502
4503 static tng_function_status tng_data_find
4504                 (tng_trajectory_t tng_data,
4505                  const int64_t id,
4506                  tng_non_particle_data_t *data)
4507 {
4508     int64_t block_index, i;
4509     tng_trajectory_frame_set_t frame_set = &tng_data->
4510                                            current_trajectory_frame_set;
4511     char block_type_flag;
4512
4513     if(tng_data->current_trajectory_frame_set_input_file_pos > 0 ||
4514        tng_data->current_trajectory_frame_set_output_file_pos > 0)
4515     {
4516         block_type_flag = TNG_TRAJECTORY_BLOCK;
4517     }
4518     else
4519     {
4520         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
4521     }
4522
4523     block_index = -1;
4524     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
4525     {
4526         for(i = frame_set->n_data_blocks; i-- ;)
4527         {
4528             *data = &frame_set->tr_data[i];
4529             if((*data)->block_id == id)
4530             {
4531                 block_index = i;
4532                 break;
4533             }
4534         }
4535         if(block_index == -1)
4536         {
4537             for(i = tng_data->n_data_blocks; i-- ;)
4538             {
4539                 *data = &tng_data->non_tr_data[i];
4540                 if((*data)->block_id == id)
4541                 {
4542                     block_index = i;
4543                     break;
4544                 }
4545             }
4546         }
4547     }
4548     else
4549     {
4550         for(i = tng_data->n_data_blocks; i-- ;)
4551         {
4552             *data = &tng_data->non_tr_data[i];
4553             if((*data)->block_id == id)
4554             {
4555                 block_index = i;
4556                 break;
4557             }
4558         }
4559     }
4560     if(block_index == -1)
4561     {
4562         return(TNG_FAILURE);
4563     }
4564     return(TNG_SUCCESS);
4565 }
4566
4567 /** Read the values of a particle data block
4568  * @param tng_data is a trajectory data container.
4569  * @param block is the block to store the data (should already contain
4570  * the block headers and the block contents).
4571  * @param offset is the reading offset to point at the place where the actual
4572  * values are stored, starting from the beginning of the block_contents. The
4573  * offset is changed during the reading.
4574  * @param datatype is the type of data of the data block (char, int, float or
4575  * double).
4576  * @param num_first_particle is the number of the first particle in the data
4577  * block. This should be the same as in the corresponding particle mapping
4578  * block.
4579  * @param n_particles is the number of particles in the data block. This should
4580  * be the same as in the corresponding particle mapping block.
4581  * @param first_frame_with_data is the frame number of the first frame with data
4582  * in this data block.
4583  * @param stride_length is the number of frames between each data entry.
4584  * @param n_frames is the number of frames in this data block.
4585  * @param n_values is the number of values per particle and frame stored in this
4586  * data block.
4587  * @param codec_id is the ID of the codec to compress the data.
4588  * @param multiplier is the multiplication factor applied to each data value
4589  * before compression. This factor is applied since some compression algorithms
4590  * work only on integers.
4591  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
4592  * error has occured.
4593  */
4594 static tng_function_status tng_particle_data_read
4595                 (tng_trajectory_t tng_data,
4596                  tng_gen_block_t block,
4597                  int *offset,
4598                  const char datatype,
4599                  const int64_t num_first_particle,
4600                  const int64_t n_particles,
4601                  const int64_t first_frame_with_data,
4602                  const int64_t stride_length,
4603                  int64_t n_frames,
4604                  const int64_t n_values,
4605                  const int64_t codec_id,
4606                  const double multiplier)
4607 {
4608     int64_t i, j, k, tot_n_particles, n_frames_div;
4609     int size, len;
4610     unsigned long data_size;
4611     char ***first_dim_values, **second_dim_values;
4612     tng_particle_data_t data;
4613     tng_trajectory_frame_set_t frame_set =
4614     &tng_data->current_trajectory_frame_set;
4615     char block_type_flag;
4616
4617     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
4618
4619     switch(datatype)
4620     {
4621     case TNG_CHAR_DATA:
4622         size = 1;
4623         break;
4624     case TNG_INT_DATA:
4625         size = sizeof(int64_t);
4626         break;
4627     case TNG_FLOAT_DATA:
4628         size = sizeof(float);
4629         break;
4630     case TNG_DOUBLE_DATA:
4631     default:
4632         size = sizeof(double);
4633     }
4634
4635     /* If the block does not exist, create it */
4636     if(tng_particle_data_find(tng_data, block->id, &data) != TNG_SUCCESS)
4637     {
4638         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
4639         {
4640             block_type_flag = TNG_TRAJECTORY_BLOCK;
4641         }
4642         else
4643         {
4644             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
4645         }
4646
4647         if(tng_particle_data_block_create(tng_data, block_type_flag) !=
4648            TNG_SUCCESS)
4649         {
4650             fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
4651                    __FILE__, __LINE__);
4652             return(TNG_CRITICAL);
4653         }
4654         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
4655         {
4656             data = &frame_set->tr_particle_data[frame_set->
4657                                                 n_particle_data_blocks - 1];
4658         }
4659         else
4660         {
4661             data = &tng_data->non_tr_particle_data[tng_data->
4662                                                    n_particle_data_blocks - 1];
4663         }
4664         data->block_id = block->id;
4665
4666         data->block_name = malloc(strlen(block->name) + 1);
4667         if(!data->block_name)
4668         {
4669             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
4670                    (int)strlen(block->name)+1, __FILE__, __LINE__);
4671             return(TNG_CRITICAL);
4672         }
4673         strcpy(data->block_name, block->name);
4674
4675         data->datatype = datatype;
4676
4677         data->values = 0;
4678         /* FIXME: Memory leak from strings. */
4679         data->strings = 0;
4680         data->n_frames = 0;
4681         data->codec_id = codec_id;
4682         data->compression_multiplier = multiplier;
4683         data->last_retrieved_frame = -1;
4684     }
4685
4686     if(/*block_type_flag == TNG_TRAJECTORY_BLOCK &&*/
4687        tng_data->current_trajectory_frame_set_input_file_pos > 0 &&
4688        tng_data->var_num_atoms_flag)
4689     {
4690         tot_n_particles = frame_set->n_particles;
4691     }
4692     else
4693     {
4694         tot_n_particles = tng_data->n_particles;
4695     }
4696
4697     n_frames_div = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
4698
4699     if(codec_id != TNG_UNCOMPRESSED)
4700     {
4701         data_size = (unsigned long)(n_frames_div * size * n_particles * n_values);
4702         switch(codec_id)
4703         {
4704         case TNG_XTC_COMPRESSION:
4705             fprintf(stderr, "TNG library: XTC compression not implemented yet.\n");
4706             break;
4707         case TNG_TNG_COMPRESSION:
4708 /*            fprintf(stderr, "TNG library: Before TNG uncompression: %"PRId64"\n", block->block_contents_size);*/
4709             if(tng_uncompress(tng_data, block, datatype,
4710                               block->block_contents + *offset,
4711                               data_size) != TNG_SUCCESS)
4712             {
4713                 fprintf(stderr, "TNG library: Could not read tng compressed block data. %s: %d\n",
4714                        __FILE__, __LINE__);
4715                 return(TNG_CRITICAL);
4716             }
4717 /*            fprintf(stderr, "TNG library: After TNG uncompression: %"PRId64"\n", block->block_contents_size);*/
4718             break;
4719 #ifdef USE_ZLIB
4720         case TNG_GZIP_COMPRESSION:
4721 /*            fprintf(stderr, "TNG library: Before GZIP uncompression: %"PRId64"\n", block->block_contents_size);*/
4722             if(tng_gzip_uncompress(tng_data, block,
4723                                    block->block_contents + *offset,
4724                                    data_size) != TNG_SUCCESS)
4725             {
4726                 fprintf(stderr, "TNG library: Could not read gzipped block data. %s: %d\n", __FILE__,
4727                     __LINE__);
4728                 return(TNG_CRITICAL);
4729             }
4730 /*            fprintf(stderr, "TNG library: After GZIP uncompression: %"PRId64"\n", block->block_contents_size);*/
4731             break;
4732 #endif
4733         }
4734     }
4735     /* Allocate memory */
4736     if(!data->values || data->n_frames != n_frames ||
4737        data->n_values_per_frame != n_values)
4738     {
4739         if(tng_allocate_particle_data_mem(tng_data, data, n_frames,
4740                                           stride_length,
4741                                           tot_n_particles, n_values) !=
4742            TNG_SUCCESS)
4743         {
4744             fprintf(stderr, "TNG library: Cannot allocate memory for particle data. %s: %d\n",
4745                    __FILE__, __LINE__);
4746             return(TNG_CRITICAL);
4747         }
4748     }
4749
4750     data->first_frame_with_data = first_frame_with_data;
4751
4752     if(datatype == TNG_CHAR_DATA)
4753     {
4754         for(i = 0; i < n_frames_div; i++)
4755         {
4756             first_dim_values = data->strings[i];
4757             for(j = num_first_particle; j < num_first_particle + n_particles;
4758                 j++)
4759             {
4760                 second_dim_values = first_dim_values[j];
4761                 for(k = 0; k < n_values; k++)
4762                 {
4763                     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
4764                               TNG_MAX_STR_LEN);
4765                     if(second_dim_values[k])
4766                     {
4767                         free(second_dim_values[k]);
4768                     }
4769                     second_dim_values[k] = malloc(len);
4770                     if(!second_dim_values[k])
4771                     {
4772                         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
4773                             len, __FILE__, __LINE__);
4774                         return(TNG_CRITICAL);
4775                     }
4776                     strncpy(second_dim_values[k],
4777                             block->block_contents+*offset, len);
4778                     *offset += len;
4779                 }
4780             }
4781         }
4782     }
4783     else
4784     {
4785         memcpy((char *)data->values + n_frames_div * size * n_values *
4786                num_first_particle,
4787                block->block_contents + *offset,
4788                block->block_contents_size - *offset);
4789         switch(datatype)
4790         {
4791         case TNG_FLOAT_DATA:
4792             if(tng_data->input_endianness_swap_func_32)
4793             {
4794                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
4795                 {
4796                     if(tng_data->input_endianness_swap_func_32(tng_data,
4797                         (int32_t *)((char *)data->values + i))
4798                         != TNG_SUCCESS)
4799                     {
4800                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4801                                 __FILE__, __LINE__);
4802                     }
4803                 }
4804             }
4805             break;
4806         case TNG_INT_DATA:
4807         case TNG_DOUBLE_DATA:
4808             if(tng_data->input_endianness_swap_func_64)
4809             {
4810                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
4811                 {
4812                     if(tng_data->input_endianness_swap_func_64(tng_data,
4813                         (int64_t *)((char *)data->values + i))
4814                         != TNG_SUCCESS)
4815                     {
4816                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4817                                 __FILE__, __LINE__);
4818                     }
4819                 }
4820             }
4821             break;
4822         case TNG_CHAR_DATA:
4823             break;
4824         }
4825     }
4826     return(TNG_SUCCESS);
4827 }
4828
4829 /** Write a particle data block
4830  * @param tng_data is a trajectory data container.
4831  * @param block is the block to store the data (should already contain
4832  * the block headers and the block contents).
4833  * @param block_index is the index number of the data block in the frame set.
4834  * @param mapping is the particle mapping that is relevant for the data block.
4835  * @param hash_mode is an option to decide whether to use the md5 hash or not.
4836  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
4837  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
4838  * error has occured.
4839  */
4840 static tng_function_status tng_particle_data_block_write
4841                 (tng_trajectory_t tng_data,
4842                  tng_gen_block_t block,
4843                  const int64_t block_index,
4844                  const tng_particle_mapping_t mapping,
4845                  const char hash_mode)
4846 {
4847     int64_t n_particles, num_first_particle, n_frames, stride_length;
4848     int64_t frame_step, data_start_pos;
4849     int64_t i, j, k;
4850     int size;
4851     size_t len, offset = 0;
4852     char dependency, temp, *temp_name;
4853     double multiplier;
4854     char ***first_dim_values, **second_dim_values;
4855     tng_trajectory_frame_set_t frame_set;
4856     tng_function_status stat;
4857
4858     tng_particle_data_t data;
4859     char block_type_flag;
4860
4861     frame_set = &tng_data->current_trajectory_frame_set;
4862
4863     /* If we have already started writing frame sets it is too late to write
4864      * non-trajectory data blocks */
4865     if(tng_data->current_trajectory_frame_set_output_file_pos > 0)
4866     {
4867         block_type_flag = TNG_TRAJECTORY_BLOCK;
4868     }
4869     else
4870     {
4871         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
4872     }
4873
4874     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
4875     {
4876         return(TNG_CRITICAL);
4877     }
4878
4879     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
4880     {
4881         data = &frame_set->tr_particle_data[block_index];
4882
4883         /* If this data block has not had any data added in this frame set
4884          * do not write it. */
4885         if(data->first_frame_with_data < frame_set->first_frame)
4886         {
4887             return(TNG_SUCCESS);
4888         }
4889
4890         stride_length = tng_max_i64(1, data->stride_length);
4891     }
4892     else
4893     {
4894         data = &tng_data->non_tr_particle_data[block_index];
4895         stride_length = 1;
4896     }
4897
4898     switch(data->datatype)
4899     {
4900     case TNG_CHAR_DATA:
4901         size = 1;
4902         break;
4903     case TNG_INT_DATA:
4904         size = sizeof(int64_t);
4905         break;
4906     case TNG_FLOAT_DATA:
4907         size = sizeof(float);
4908         break;
4909     case TNG_DOUBLE_DATA:
4910     default:
4911         size = sizeof(double);
4912     }
4913
4914     len = strlen(data->block_name) + 1;
4915
4916     if(!block->name || strlen(block->name) < len)
4917     {
4918         temp_name = realloc(block->name, len);
4919         if(!temp_name)
4920         {
4921             fprintf(stderr, "TNG library: Cannot allocate memory (%lud bytes). %s: %d\n", len,
4922                    __FILE__, __LINE__);
4923             free(block->name);
4924             block->name = 0;
4925             return(TNG_CRITICAL);
4926         }
4927         block->name = temp_name;
4928     }
4929     strncpy(block->name, data->block_name, len);
4930     block->id = data->block_id;
4931
4932     /* If writing frame independent data data->n_frames is 0, but n_frames
4933        is used for the loop writing the data (and reserving memory) and needs
4934        to be at least 1 */
4935     n_frames = tng_max_i64(1, data->n_frames);
4936
4937     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
4938     {
4939         /* If the frame set is finished before writing the full number of frames
4940            make sure the data block is not longer than the frame set. */
4941         n_frames = tng_min_i64(n_frames, frame_set->n_frames);
4942
4943         n_frames -= (data->first_frame_with_data - frame_set->first_frame);
4944     }
4945
4946     frame_step = (n_frames % stride_length) ? n_frames / stride_length + 1:
4947                  n_frames / stride_length;
4948
4949     /* TNG compression will use compression precision to get integers from
4950      * floating point data. The compression multiplier stores that information
4951      * to be able to return the precision of the compressed data. */
4952     if(data->codec_id == TNG_TNG_COMPRESSION)
4953     {
4954         data->compression_multiplier = tng_data->compression_precision;
4955     }
4956     /* Uncompressed data blocks do not use compression multipliers at all.
4957      * GZip compression does not need it either. */
4958     else if(data->codec_id == TNG_UNCOMPRESSED || data->codec_id == TNG_GZIP_COMPRESSION)
4959     {
4960         data->compression_multiplier = 1.0;
4961     }
4962
4963     if(mapping && mapping->n_particles != 0)
4964     {
4965         n_particles = mapping->n_particles;
4966         num_first_particle = mapping->num_first_particle;
4967     }
4968     else
4969     {
4970         num_first_particle = 0;
4971         if(tng_data->var_num_atoms_flag)
4972         {
4973             n_particles = frame_set->n_particles;
4974         }
4975         else
4976         {
4977             n_particles = tng_data->n_particles;
4978         }
4979     }
4980
4981     block->block_contents_size = sizeof(char) * 2 +
4982                                  sizeof(data->n_values_per_frame) +
4983                                  sizeof(data->codec_id) +
4984                                  sizeof(num_first_particle) +
4985                                  sizeof(n_particles);
4986
4987     if(stride_length > 1)
4988     {
4989         block->block_contents_size += sizeof(data->first_frame_with_data) +
4990                                       sizeof(data->stride_length);
4991     }
4992
4993     if(data->codec_id != TNG_UNCOMPRESSED)
4994     {
4995         block->block_contents_size += sizeof(data->compression_multiplier);
4996     }
4997
4998     if(block_type_flag == TNG_TRAJECTORY_BLOCK && data->n_frames > 0)
4999     {
5000         dependency = TNG_FRAME_DEPENDENT + TNG_PARTICLE_DEPENDENT;
5001     }
5002     else
5003     {
5004         dependency = TNG_PARTICLE_DEPENDENT;
5005     }
5006     if(dependency & TNG_FRAME_DEPENDENT)
5007     {
5008         block->block_contents_size += sizeof(char);
5009     }
5010
5011     data_start_pos = block->block_contents_size;
5012
5013     if(data->datatype == TNG_CHAR_DATA)
5014     {
5015         for(i = n_frames; i--;)
5016         {
5017             first_dim_values = data->strings[i];
5018             for(j = num_first_particle; j < num_first_particle + n_particles;
5019                 j++)
5020             {
5021                 second_dim_values = first_dim_values[j];
5022                 for(k = data->n_values_per_frame; k--;)
5023                 {
5024                     block->block_contents_size +=
5025                     strlen(second_dim_values[k]) + 1;
5026                 }
5027             }
5028         }
5029     }
5030     else
5031     {
5032         block->block_contents_size += size * frame_step *
5033                                       n_particles * data->n_values_per_frame;
5034     }
5035
5036     if(block->block_contents)
5037     {
5038         free(block->block_contents);
5039     }
5040     block->block_contents = malloc(block->block_contents_size);
5041     if(!block->block_contents)
5042     {
5043         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5044                block->block_contents_size, __FILE__, __LINE__);
5045         return(TNG_CRITICAL);
5046     }
5047
5048
5049     memcpy(block->block_contents, &data->datatype, sizeof(char));
5050     offset += sizeof(char);
5051
5052     memcpy(block->block_contents+offset, &dependency, sizeof(char));
5053     offset += sizeof(char);
5054
5055     if(dependency & TNG_FRAME_DEPENDENT)
5056     {
5057         if(stride_length > 1)
5058         {
5059             temp = 1;
5060         }
5061         else
5062         {
5063             temp = 0;
5064         }
5065         memcpy(block->block_contents+offset, &temp, sizeof(char));
5066         offset += sizeof(char);
5067     }
5068
5069     memcpy(block->block_contents+offset, &data->n_values_per_frame,
5070            sizeof(data->n_values_per_frame));
5071     if(tng_data->output_endianness_swap_func_64)
5072     {
5073         if(tng_data->output_endianness_swap_func_64(tng_data,
5074            (int64_t *)block->header_contents+offset)
5075             != TNG_SUCCESS)
5076         {
5077             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5078                     __FILE__, __LINE__);
5079         }
5080     }
5081     offset += sizeof(data->n_values_per_frame);
5082
5083     memcpy(block->block_contents+offset, &data->codec_id,
5084            sizeof(data->codec_id));
5085     if(tng_data->output_endianness_swap_func_64)
5086     {
5087         if(tng_data->output_endianness_swap_func_64(tng_data,
5088            (int64_t *)block->header_contents+offset)
5089             != TNG_SUCCESS)
5090         {
5091             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5092                     __FILE__, __LINE__);
5093         }
5094     }
5095     offset += sizeof(data->codec_id);
5096
5097     if(data->codec_id != TNG_UNCOMPRESSED)
5098     {
5099         memcpy(block->block_contents+offset, &data->compression_multiplier,
5100                sizeof(data->compression_multiplier));
5101         if(tng_data->output_endianness_swap_func_64)
5102         {
5103             if(tng_data->output_endianness_swap_func_64(tng_data,
5104                (int64_t *)block->header_contents+offset)
5105                 != TNG_SUCCESS)
5106             {
5107                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5108                         __FILE__, __LINE__);
5109             }
5110         }
5111         offset += sizeof(data->compression_multiplier);
5112     }
5113
5114     if(data->n_frames > 0 && stride_length > 1)
5115     {
5116         /* FIXME: first_frame_with_data is not reliably set */
5117         if(data->first_frame_with_data == 0)
5118         {
5119             data->first_frame_with_data = frame_set->first_frame;
5120         }
5121         memcpy(block->block_contents+offset, &data->first_frame_with_data,
5122                sizeof(data->first_frame_with_data));
5123         if(tng_data->output_endianness_swap_func_64)
5124         {
5125             if(tng_data->output_endianness_swap_func_64(tng_data,
5126                (int64_t *)block->header_contents+offset)
5127                 != TNG_SUCCESS)
5128             {
5129                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5130                         __FILE__, __LINE__);
5131             }
5132         }
5133         offset += sizeof(data->first_frame_with_data);
5134
5135         memcpy(block->block_contents+offset, &stride_length,
5136                sizeof(stride_length));
5137         if(tng_data->output_endianness_swap_func_64)
5138         {
5139             if(tng_data->output_endianness_swap_func_64(tng_data,
5140                (int64_t *)block->header_contents+offset)
5141                 != TNG_SUCCESS)
5142             {
5143                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5144                         __FILE__, __LINE__);
5145             }
5146         }
5147         offset += sizeof(stride_length);
5148     }
5149
5150
5151     memcpy(block->block_contents+offset, &num_first_particle,
5152            sizeof(num_first_particle));
5153     if(tng_data->output_endianness_swap_func_64)
5154     {
5155         if(tng_data->output_endianness_swap_func_64(tng_data,
5156            (int64_t *)block->header_contents+offset)
5157             != TNG_SUCCESS)
5158         {
5159             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5160                     __FILE__, __LINE__);
5161         }
5162     }
5163     offset += sizeof(num_first_particle);
5164
5165     memcpy(block->block_contents+offset, &n_particles, sizeof(n_particles));
5166     if(tng_data->output_endianness_swap_func_64)
5167     {
5168         if(tng_data->output_endianness_swap_func_64(tng_data,
5169            (int64_t *)block->header_contents+offset)
5170             != TNG_SUCCESS)
5171         {
5172             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5173                     __FILE__, __LINE__);
5174         }
5175     }
5176     offset += sizeof(n_particles);
5177
5178     if(data->datatype == TNG_CHAR_DATA)
5179     {
5180         if(data->strings)
5181         {
5182             for(i = 0; i < frame_step; i++)
5183             {
5184                 first_dim_values = data->strings[i];
5185                 for(j = num_first_particle; j < num_first_particle + n_particles;
5186                     j++)
5187                 {
5188                     second_dim_values = first_dim_values[j];
5189                     for(k = 0; k < data->n_values_per_frame; k++)
5190                     {
5191                         len = (unsigned int)strlen(second_dim_values[k]) + 1;
5192                         strncpy(block->block_contents+offset,
5193                                 second_dim_values[k], len);
5194                         offset += len;
5195                     }
5196                 }
5197             }
5198         }
5199     }
5200     else if(data->values)
5201     {
5202         memcpy(block->block_contents + offset, data->values,
5203                block->block_contents_size - offset);
5204
5205         switch(data->datatype)
5206         {
5207         case TNG_FLOAT_DATA:
5208             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
5209                data->codec_id == TNG_TNG_COMPRESSION)
5210             {
5211                 if(tng_data->input_endianness_swap_func_32)
5212                 {
5213                     for(i = offset; i < block->block_contents_size; i+=size)
5214                     {
5215                         if(tng_data->input_endianness_swap_func_32(tng_data,
5216                            (int32_t *)(block->block_contents + i))
5217                            != TNG_SUCCESS)
5218                         {
5219                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5220                                     __FILE__, __LINE__);
5221                         }
5222                     }
5223                 }
5224             }
5225             else
5226             {
5227                 multiplier = data->compression_multiplier;
5228                 if(fabs(multiplier - 1.0) > 0.00001 ||
5229                    tng_data->input_endianness_swap_func_32)
5230                 {
5231                     for(i = offset; i < block->block_contents_size; i+=size)
5232                     {
5233                         *(float *)(block->block_contents + i) *= (float)multiplier;
5234                         if(tng_data->input_endianness_swap_func_32 &&
5235                         tng_data->input_endianness_swap_func_32(tng_data,
5236                         (int32_t *)(block->block_contents + i))
5237                         != TNG_SUCCESS)
5238                         {
5239                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5240                                     __FILE__, __LINE__);
5241                         }
5242                     }
5243                 }
5244             }
5245             break;
5246         case TNG_INT_DATA:
5247             if(tng_data->input_endianness_swap_func_64)
5248             {
5249                 for(i = offset; i < block->block_contents_size; i+=size)
5250                 {
5251                     if(tng_data->input_endianness_swap_func_64(tng_data,
5252                        (int64_t *)(block->block_contents + i))
5253                        != TNG_SUCCESS)
5254                     {
5255                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5256                                 __FILE__, __LINE__);
5257                     }
5258                 }
5259             }
5260             break;
5261         case TNG_DOUBLE_DATA:
5262             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
5263                data->codec_id == TNG_TNG_COMPRESSION)
5264             {
5265                 if(tng_data->input_endianness_swap_func_64)
5266                 {
5267                     for(i = offset; i < block->block_contents_size; i+=size)
5268                     {
5269                         if(tng_data->input_endianness_swap_func_64(tng_data,
5270                            (int64_t *)(block->block_contents + i))
5271                            != TNG_SUCCESS)
5272                         {
5273                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5274                                     __FILE__, __LINE__);
5275                         }
5276                     }
5277                 }
5278             }
5279             else
5280             {
5281                 multiplier = data->compression_multiplier;
5282                 if(fabs(multiplier - 1.0) > 0.00001 ||
5283                    tng_data->input_endianness_swap_func_64)
5284                 {
5285                     for(i = offset; i < block->block_contents_size; i+=size)
5286                     {
5287                         *(double *)(block->block_contents + i) *= multiplier;
5288                         if(tng_data->input_endianness_swap_func_64 &&
5289                         tng_data->input_endianness_swap_func_64(tng_data,
5290                         (int64_t *)(block->block_contents + i))
5291                         != TNG_SUCCESS)
5292                         {
5293                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5294                                     __FILE__, __LINE__);
5295                         }
5296                     }
5297                 }
5298             }
5299             break;
5300         case TNG_CHAR_DATA:
5301             break;
5302         }
5303     }
5304     else
5305     {
5306         memset(block->block_contents+offset, 0, block->block_contents_size - offset);
5307     }
5308
5309     frame_set->n_written_frames += frame_set->n_unwritten_frames;
5310     frame_set->n_unwritten_frames = 0;
5311
5312     if(block_type_flag == TNG_NON_TRAJECTORY_BLOCK || frame_set->n_written_frames > 0)
5313     {
5314         switch(data->codec_id)
5315         {
5316         case TNG_XTC_COMPRESSION:
5317             fprintf(stderr, "TNG library: XTC compression not implemented yet.\n");
5318             data->codec_id = TNG_UNCOMPRESSED;
5319             break;
5320         case TNG_TNG_COMPRESSION:
5321             stat = tng_compress(tng_data, block, frame_step,
5322                                 n_particles, data->datatype,
5323                                 block->block_contents + data_start_pos);
5324             if(stat != TNG_SUCCESS)
5325             {
5326                 fprintf(stderr, "TNG library: Could not write tng compressed block data. %s: %d\n",
5327                     __FILE__, __LINE__);
5328                 if(stat == TNG_CRITICAL)
5329                 {
5330                     return(TNG_CRITICAL);
5331                 }
5332                 /* Set the data again, but with no compression (to write only
5333                  * the relevant data) */
5334                 data->codec_id = TNG_UNCOMPRESSED;
5335                 stat = tng_particle_data_block_write(tng_data, block,
5336                                                      block_index, mapping,
5337                                                      hash_mode);
5338                 return(stat);
5339             }
5340             break;
5341 #ifdef USE_ZLIB
5342         case TNG_GZIP_COMPRESSION:
5343     /*         fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size);*/
5344             stat = tng_gzip_compress(tng_data, block,
5345                                      block->block_contents + data_start_pos,
5346                                      block->block_contents_size - data_start_pos);
5347             if(stat != TNG_SUCCESS)
5348             {
5349                 fprintf(stderr, "TNG library: Could not write gzipped block data. %s: %d\n", __FILE__,
5350                     __LINE__);
5351                 if(stat == TNG_CRITICAL)
5352                 {
5353                     return(TNG_CRITICAL);
5354                 }
5355                 /* Set the data again, but with no compression (to write only
5356                  * the relevant data) */
5357                 data->codec_id = TNG_UNCOMPRESSED;
5358                 stat = tng_particle_data_block_write(tng_data, block,
5359                                                      block_index, mapping,
5360                                                      hash_mode);
5361                 return(stat);
5362             }
5363     /*         fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size);*/
5364             break;
5365 #endif
5366         }
5367     }
5368
5369     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
5370     {
5371         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
5372                tng_data->output_file_path, __FILE__, __LINE__);
5373         return(TNG_CRITICAL);
5374     }
5375
5376     if(fwrite(block->block_contents, block->block_contents_size, 1,
5377         tng_data->output_file) != 1)
5378     {
5379         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__,
5380                 __LINE__);
5381         return(TNG_CRITICAL);
5382     }
5383
5384     return(TNG_SUCCESS);
5385 }
5386
5387 /* TEST: */
5388 /** Create a non-particle data block
5389  * @param tng_data is a trajectory data container.
5390  * @param block_type_flag specifies if this is a trajectory block or a
5391  * non-trajectory block. (TNG_TRAJECTORY_BLOCK or TNG_NON_TRAJECTORY_BLOCK)
5392  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5393  * error has occured.
5394  */
5395 static tng_function_status tng_data_block_create
5396                 (tng_trajectory_t tng_data,
5397                  const char block_type_flag)
5398 {
5399     tng_trajectory_frame_set_t frame_set =
5400     &tng_data->current_trajectory_frame_set;
5401
5402     tng_non_particle_data_t data;
5403
5404     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5405     {
5406         frame_set->n_data_blocks++;
5407         data = realloc(frame_set->tr_data, sizeof(struct tng_non_particle_data) *
5408                        frame_set->n_data_blocks);
5409         if(!data)
5410         {
5411             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
5412                 sizeof(struct tng_non_particle_data) * frame_set->n_data_blocks,
5413                 __FILE__, __LINE__);
5414             free(frame_set->tr_data);
5415             frame_set->tr_data = 0;
5416             return(TNG_CRITICAL);
5417         }
5418         frame_set->tr_data = data;
5419     }
5420     else
5421     {
5422         tng_data->n_data_blocks++;
5423         data = realloc(tng_data->non_tr_data, sizeof(struct tng_non_particle_data) *
5424                         tng_data->n_data_blocks);
5425         if(!data)
5426         {
5427             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
5428                 sizeof(struct tng_non_particle_data) * tng_data->n_data_blocks,
5429                 __FILE__, __LINE__);
5430             free(tng_data->non_tr_data);
5431             tng_data->non_tr_data = 0;
5432             return(TNG_CRITICAL);
5433         }
5434         tng_data->non_tr_data = data;
5435     }
5436
5437     return(TNG_SUCCESS);
5438 }
5439
5440 /* TEST: */
5441 /** Allocate memory for storing non-particle data.
5442  * The allocated block will be refered to by data->values.
5443  * @param tng_data is a trajectory data container.
5444  * @param data is the data struct, which will contain the allocated memory in
5445  * data->values.
5446  * @param n_frames is the number of frames of data to store.
5447  * @param n_values_per_frame is the number of data values per frame.
5448  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5449  * error has occured.
5450  */
5451 static tng_function_status tng_allocate_data_mem
5452                 (tng_trajectory_t tng_data,
5453                  tng_non_particle_data_t data,
5454                  int64_t n_frames,
5455                  int64_t stride_length,
5456                  const int64_t n_values_per_frame)
5457 {
5458     void **values;
5459     int64_t i, j, size, frame_alloc;
5460     (void)tng_data;
5461
5462     if(n_values_per_frame == 0)
5463     {
5464         return(TNG_FAILURE);
5465     }
5466
5467     if(data->strings && data->datatype == TNG_CHAR_DATA)
5468     {
5469         for(i = data->n_frames; i--;)
5470         {
5471             for(j = data->n_values_per_frame; j--;)
5472             {
5473                 if(data->strings[i][j])
5474                 {
5475                     free(data->strings[i][j]);
5476                     data->strings[i][j] = 0;
5477                 }
5478             }
5479             free(data->strings[i]);
5480             data->strings[i] = 0;
5481         }
5482         free(data->strings);
5483     }
5484     data->n_frames = n_frames;
5485     data->stride_length = tng_max_i64(1, stride_length);
5486     n_frames = tng_max_i64(1, n_frames);
5487     data->n_values_per_frame = n_values_per_frame;
5488     frame_alloc = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
5489
5490     if(data->datatype == TNG_CHAR_DATA)
5491     {
5492         data->strings = malloc(sizeof(char **) * frame_alloc);
5493         for(i = frame_alloc; i-- ;)
5494         {
5495             data->strings[i] = malloc(sizeof(char *) * n_values_per_frame);
5496             if(!data->strings[i])
5497             {
5498                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5499                        n_values_per_frame,
5500                        __FILE__, __LINE__);
5501                 return(TNG_CRITICAL);
5502             }
5503             for(j = n_values_per_frame; j--;)
5504             {
5505                 data->strings[i][j] = 0;
5506             }
5507         }
5508     }
5509     else
5510     {
5511         switch(data->datatype)
5512         {
5513         case TNG_INT_DATA:
5514             size = sizeof(int64_t);
5515             break;
5516         case TNG_FLOAT_DATA:
5517             size = sizeof(float);
5518             break;
5519         case TNG_DOUBLE_DATA:
5520         default:
5521             size = sizeof(double);
5522         }
5523
5524         values = realloc(data->values,
5525                          size * frame_alloc *
5526                          n_values_per_frame);
5527         if(!values)
5528         {
5529             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5530                    size * frame_alloc *
5531                    n_values_per_frame,
5532                    __FILE__, __LINE__);
5533             free(data->values);
5534             data->values = 0;
5535             return(TNG_CRITICAL);
5536         }
5537         data->values = values;
5538     }
5539
5540     return(TNG_SUCCESS);
5541 }
5542
5543 /** Read the values of a non-particle data block
5544  * @param tng_data is a trajectory data container.
5545  * @param block is the block to store the data (should already contain
5546  * the block headers and the block contents).
5547  * @param offset is the reading offset to point at the place where the actual
5548  * values are stored, starting from the beginning of the block_contents. The
5549  * offset is changed during the reading.
5550  * @param datatype is the type of data of the data block (char, int, float or
5551  * double).
5552  * @param first_frame_with_data is the frame number of the first frame with data
5553  * in this data block.
5554  * @param stride_length is the number of frames between each data entry.
5555  * @param n_frames is the number of frames in this data block.
5556  * @param n_values is the number of values per frame stored in this data block.
5557  * @param codec_id is the ID of the codec to compress the data.
5558  * @param multiplier is the multiplication factor applied to each data value
5559  * before compression. This factor is applied since some compression algorithms
5560  * work only on integers.
5561  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5562  * error has occured.
5563  */
5564 static tng_function_status tng_data_read(tng_trajectory_t tng_data,
5565                                          tng_gen_block_t block,
5566                                          int *offset,
5567                                          const char datatype,
5568                                          const int64_t first_frame_with_data,
5569                                          const int64_t stride_length,
5570                                          int64_t n_frames,
5571                                          const int64_t n_values,
5572                                          const int64_t codec_id,
5573                                          const double multiplier)
5574 {
5575     int64_t i, j, n_frames_div;
5576     int size, len;
5577 #ifdef USE_ZLIB
5578     unsigned long data_size;
5579 #endif
5580     tng_non_particle_data_t data;
5581     tng_trajectory_frame_set_t frame_set =
5582     &tng_data->current_trajectory_frame_set;
5583     char block_type_flag;
5584
5585     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
5586
5587 /*     fprintf(stderr, "TNG library: %s\n", block->name);*/
5588
5589     switch(datatype)
5590     {
5591     case TNG_CHAR_DATA:
5592         size = 1;
5593         break;
5594     case TNG_INT_DATA:
5595         size = sizeof(int64_t);
5596         break;
5597     case TNG_FLOAT_DATA:
5598         size = sizeof(float);
5599         break;
5600     case TNG_DOUBLE_DATA:
5601     default:
5602         size = sizeof(double);
5603     }
5604
5605     /* If the block does not exist, create it */
5606     if(tng_data_find(tng_data, block->id, &data) != TNG_SUCCESS)
5607     {
5608         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
5609         {
5610             block_type_flag = TNG_TRAJECTORY_BLOCK;
5611         }
5612         else
5613         {
5614             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5615         }
5616
5617         if(tng_data_block_create(tng_data, block_type_flag) !=
5618             TNG_SUCCESS)
5619         {
5620             fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
5621                    __FILE__, __LINE__);
5622             return(TNG_CRITICAL);
5623         }
5624         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5625         {
5626             data = &frame_set->tr_data[frame_set->n_data_blocks - 1];
5627         }
5628         else
5629         {
5630             data = &tng_data->non_tr_data[tng_data->n_data_blocks - 1];
5631         }
5632         data->block_id = block->id;
5633
5634         data->block_name = malloc(strlen(block->name) + 1);
5635         if(!data->block_name)
5636         {
5637             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
5638                    (int)strlen(block->name)+1, __FILE__, __LINE__);
5639             return(TNG_CRITICAL);
5640         }
5641         strcpy(data->block_name, block->name);
5642
5643         data->datatype = datatype;
5644
5645         data->values = 0;
5646         /* FIXME: Memory leak from strings. */
5647         data->strings = 0;
5648         data->n_frames = 0;
5649         data->codec_id = codec_id;
5650         data->compression_multiplier = multiplier;
5651         data->last_retrieved_frame = -1;
5652     }
5653
5654     n_frames_div = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
5655
5656     if(codec_id != TNG_UNCOMPRESSED)
5657     {
5658         switch(codec_id)
5659         {
5660 #ifdef USE_ZLIB
5661         case TNG_GZIP_COMPRESSION:
5662             data_size = n_frames_div * size * n_values;
5663     /*         fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size); */
5664             if(tng_gzip_uncompress(tng_data, block,
5665                                    block->block_contents + *offset,
5666                                    data_size) != TNG_SUCCESS)
5667             {
5668                 fprintf(stderr, "TNG library: Could not read gzipped block data. %s: %d\n", __FILE__,
5669                     __LINE__);
5670                 return(TNG_CRITICAL);
5671             }
5672     /*         fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size); */
5673             break;
5674 #endif
5675         }
5676     }
5677
5678     /* Allocate memory */
5679     if(!data->values || data->n_frames != n_frames ||
5680        data->n_values_per_frame != n_values)
5681     {
5682         if(tng_allocate_data_mem(tng_data, data, n_frames, stride_length,
5683                                  n_values) !=
5684            TNG_SUCCESS)
5685         {
5686             fprintf(stderr, "TNG library: Cannot allocate memory for data. %s: %d\n",
5687                    __FILE__, __LINE__);
5688             return(TNG_CRITICAL);
5689         }
5690     }
5691
5692     data->first_frame_with_data = first_frame_with_data;
5693
5694     if(datatype == TNG_CHAR_DATA)
5695     {
5696         for(i = 0; i < n_frames_div; i++)
5697         {
5698             for(j = 0; j < n_values; j++)
5699             {
5700                 len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
5701                               TNG_MAX_STR_LEN);
5702                 if(data->strings[i][j])
5703                 {
5704                     free(data->strings[i][j]);
5705                 }
5706                 data->strings[i][j] = malloc(len);
5707                 if(!data->strings[i][j])
5708                 {
5709                     fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
5710                            len, __FILE__, __LINE__);
5711                     return(TNG_CRITICAL);
5712                 }
5713                 strncpy(data->strings[i][j], block->block_contents+*offset,
5714                         len);
5715                 *offset += len;
5716             }
5717         }
5718     }
5719     else
5720     {
5721         memcpy(data->values, block->block_contents + *offset,
5722                block->block_contents_size - *offset);
5723         switch(datatype)
5724         {
5725         case TNG_FLOAT_DATA:
5726             if(tng_data->input_endianness_swap_func_32)
5727             {
5728                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
5729                 {
5730                     if(tng_data->input_endianness_swap_func_32(tng_data,
5731                         (int32_t *)((char *)data->values + i))
5732                         != TNG_SUCCESS)
5733                     {
5734                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5735                                 __FILE__, __LINE__);
5736                     }
5737                 }
5738             }
5739             break;
5740         case TNG_INT_DATA:
5741         case TNG_DOUBLE_DATA:
5742             if(tng_data->input_endianness_swap_func_64)
5743             {
5744                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
5745                 {
5746                     if(tng_data->input_endianness_swap_func_64(tng_data,
5747                         (int64_t *)((char *)data->values + i))
5748                         != TNG_SUCCESS)
5749                     {
5750                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5751                                 __FILE__, __LINE__);
5752                     }
5753                 }
5754             }
5755             break;
5756         case TNG_CHAR_DATA:
5757             break;
5758         }
5759     }
5760     return(TNG_SUCCESS);
5761 }
5762
5763 /** Write a non-particle data block
5764  * @param tng_data is a trajectory data container.
5765  * @param block is the block to store the data (should already contain
5766  * the block headers and the block contents).
5767  * @param block_index is the index number of the data block in the frame set.
5768  * @param hash_mode is an option to decide whether to use the md5 hash or not.
5769  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
5770  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5771  * error has occured.
5772  */
5773 static tng_function_status tng_data_block_write(tng_trajectory_t tng_data,
5774                                                 tng_gen_block_t block,
5775                                                 const int64_t block_index,
5776                                                 const char hash_mode)
5777 {
5778     int64_t n_frames, stride_length, frame_step;
5779     int64_t i, j;
5780     int offset = 0, size;
5781     unsigned int len;
5782 #ifdef USE_ZLIB
5783     int data_start_pos;
5784     tng_function_status stat;
5785 #endif
5786     char temp, dependency, *temp_name;
5787     double multiplier;
5788     tng_trajectory_frame_set_t frame_set =
5789     &tng_data->current_trajectory_frame_set;
5790
5791     tng_non_particle_data_t data;
5792     char block_type_flag;
5793
5794     /* If we have already started writing frame sets it is too late to write
5795      * non-trajectory data blocks */
5796     if(tng_data->current_trajectory_frame_set_output_file_pos > 0)
5797     {
5798         block_type_flag = TNG_TRAJECTORY_BLOCK;
5799     }
5800     else
5801     {
5802         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5803     }
5804
5805     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
5806     {
5807         return(TNG_CRITICAL);
5808     }
5809
5810     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5811     {
5812         data = &frame_set->tr_data[block_index];
5813
5814         /* If this data block has not had any data added in this frame set
5815          * do not write it. */
5816         if(data->first_frame_with_data < frame_set->first_frame)
5817         {
5818             return(TNG_SUCCESS);
5819         }
5820
5821         stride_length = tng_max_i64(1, data->stride_length);
5822     }
5823     else
5824     {
5825         data = &tng_data->non_tr_data[block_index];
5826         stride_length = 1;
5827     }
5828
5829     switch(data->datatype)
5830     {
5831     case TNG_CHAR_DATA:
5832         size = 1;
5833         break;
5834     case TNG_INT_DATA:
5835         size = sizeof(int64_t);
5836         break;
5837     case TNG_FLOAT_DATA:
5838         size = sizeof(float);
5839         break;
5840     case TNG_DOUBLE_DATA:
5841     default:
5842         size = sizeof(double);
5843     }
5844
5845     len = (unsigned int)strlen(data->block_name) + 1;
5846
5847     if(!block->name || strlen(block->name) < len)
5848     {
5849         temp_name = realloc(block->name, len);
5850         if(!temp_name)
5851         {
5852             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len+1,
5853                    __FILE__, __LINE__);
5854             free(block->name);
5855             block->name = 0;
5856             return(TNG_CRITICAL);
5857         }
5858         block->name = temp_name;
5859     }
5860     strncpy(block->name, data->block_name, len);
5861     block->id = data->block_id;
5862
5863     /* If writing frame independent data data->n_frames is 0, but n_frames
5864        is used for the loop writing the data (and reserving memory) and needs
5865        to be at least 1 */
5866     n_frames = tng_max_i64(1, data->n_frames);
5867
5868     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5869     {
5870         /* If the frame set is finished before writing the full number of frames
5871            make sure the data block is not longer than the frame set. */
5872         n_frames = tng_min_i64(n_frames, frame_set->n_frames);
5873
5874         n_frames -= (data->first_frame_with_data - frame_set->first_frame);
5875     }
5876
5877     frame_step = (n_frames % stride_length) ? n_frames / stride_length + 1:
5878                  n_frames / stride_length;
5879
5880     /* TNG compression will use compression precision to get integers from
5881      * floating point data. The compression multiplier stores that information
5882      * to be able to return the precision of the compressed data. */
5883     if(data->codec_id == TNG_TNG_COMPRESSION)
5884     {
5885         data->compression_multiplier = tng_data->compression_precision;
5886     }
5887     /* Uncompressed data blocks do not use compression multipliers at all.
5888      * GZip compression does not need it either. */
5889     else if(data->codec_id == TNG_UNCOMPRESSED || data->codec_id == TNG_GZIP_COMPRESSION)
5890     {
5891         data->compression_multiplier = 1.0;
5892     }
5893
5894     block->block_contents_size = sizeof(char) * 2 +
5895                                  sizeof(data->n_values_per_frame) +
5896                                  sizeof(data->codec_id);
5897
5898     if(stride_length > 1)
5899     {
5900         block->block_contents_size += sizeof(data->first_frame_with_data) +
5901                                       sizeof(data->stride_length);
5902     }
5903
5904     if(data->codec_id != TNG_UNCOMPRESSED)
5905     {
5906         block->block_contents_size += sizeof(data->compression_multiplier);
5907     }
5908
5909     if(block_type_flag == TNG_TRAJECTORY_BLOCK && data->n_frames > 0)
5910     {
5911         dependency = TNG_FRAME_DEPENDENT;
5912     }
5913     else
5914     {
5915         dependency = 0;
5916     }
5917     if(dependency & TNG_FRAME_DEPENDENT)
5918     {
5919         block->block_contents_size += sizeof(char);
5920     }
5921
5922 #ifdef USE_ZLIB
5923     data_start_pos = block->block_contents_size;
5924 #endif
5925
5926     if(data->datatype == TNG_CHAR_DATA)
5927     {
5928         for(i = n_frames; i--;)
5929         {
5930             for(j = data->n_values_per_frame; j--;)
5931             {
5932                 block->block_contents_size += strlen(data->strings[i][j]) + 1;
5933             }
5934         }
5935     }
5936     else
5937     {
5938         block->block_contents_size += size * frame_step *
5939         data->n_values_per_frame;
5940     }
5941
5942     if(block->block_contents)
5943     {
5944         free(block->block_contents);
5945     }
5946     block->block_contents = malloc(block->block_contents_size);
5947     if(!block->block_contents)
5948     {
5949         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5950                block->block_contents_size, __FILE__, __LINE__);
5951         return(TNG_CRITICAL);
5952     }
5953
5954
5955     memcpy(block->block_contents, &data->datatype, sizeof(char));
5956     offset += sizeof(char);
5957
5958     memcpy(block->block_contents+offset, &dependency, sizeof(char));
5959     offset += sizeof(char);
5960
5961     if(dependency & TNG_FRAME_DEPENDENT)
5962     {
5963         if(stride_length > 1)
5964         {
5965             temp = 1;
5966         }
5967         else
5968         {
5969             temp = 0;
5970         }
5971         memcpy(block->block_contents+offset, &temp, sizeof(char));
5972         offset += sizeof(char);
5973     }
5974
5975     memcpy(block->block_contents+offset, &data->n_values_per_frame,
5976            sizeof(data->n_values_per_frame));
5977     if(tng_data->output_endianness_swap_func_64)
5978     {
5979         if(tng_data->output_endianness_swap_func_64(tng_data,
5980            (int64_t *)block->header_contents+offset)
5981             != TNG_SUCCESS)
5982         {
5983             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5984                     __FILE__, __LINE__);
5985         }
5986     }
5987     offset += sizeof(data->n_values_per_frame);
5988
5989     memcpy(block->block_contents+offset, &data->codec_id,
5990            sizeof(data->codec_id));
5991     if(tng_data->output_endianness_swap_func_64)
5992     {
5993         if(tng_data->output_endianness_swap_func_64(tng_data,
5994            (int64_t *)block->header_contents+offset)
5995             != TNG_SUCCESS)
5996         {
5997             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5998                     __FILE__, __LINE__);
5999         }
6000     }
6001     offset += sizeof(data->codec_id);
6002
6003     if(data->codec_id != TNG_UNCOMPRESSED)
6004     {
6005         memcpy(block->block_contents+offset, &data->compression_multiplier,
6006                sizeof(data->compression_multiplier));
6007         if(tng_data->output_endianness_swap_func_64)
6008         {
6009             if(tng_data->output_endianness_swap_func_64(tng_data,
6010             (int64_t *)block->header_contents+offset)
6011                 != TNG_SUCCESS)
6012             {
6013                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6014                         __FILE__, __LINE__);
6015             }
6016         }
6017         offset += sizeof(data->compression_multiplier);
6018     }
6019
6020     if(data->n_frames > 0 && stride_length > 1)
6021     {
6022         /* FIXME: first_frame_with_data is not reliably set */
6023         if(data->first_frame_with_data == 0)
6024         {
6025             data->first_frame_with_data = frame_set->first_frame;
6026         }
6027         memcpy(block->block_contents+offset, &data->first_frame_with_data,
6028                sizeof(data->first_frame_with_data));
6029         if(tng_data->output_endianness_swap_func_64)
6030         {
6031             if(tng_data->output_endianness_swap_func_64(tng_data,
6032             (int64_t *)block->header_contents+offset)
6033                 != TNG_SUCCESS)
6034             {
6035                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6036                         __FILE__, __LINE__);
6037             }
6038         }
6039         offset += sizeof(data->first_frame_with_data);
6040
6041         memcpy(block->block_contents+offset, &stride_length,
6042                sizeof(data->stride_length));
6043         if(tng_data->output_endianness_swap_func_64)
6044         {
6045             if(tng_data->output_endianness_swap_func_64(tng_data,
6046             (int64_t *)block->header_contents+offset)
6047                 != TNG_SUCCESS)
6048             {
6049                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6050                         __FILE__, __LINE__);
6051             }
6052         }
6053         offset += sizeof(data->stride_length);
6054     }
6055
6056     if(data->datatype == TNG_CHAR_DATA)
6057     {
6058         if(data->strings)
6059         {
6060             for(i = 0; i < frame_step; i++)
6061             {
6062                 for(j = 0; j < data->n_values_per_frame; j++)
6063                 {
6064                     len = (unsigned int)strlen(data->strings[i][j]) + 1;
6065                     strncpy(block->block_contents+offset, data->strings[i][j],
6066                             len);
6067                     offset += len;
6068                 }
6069             }
6070         }
6071     }
6072     else if(data->values)
6073     {
6074         memcpy(block->block_contents + offset, data->values,
6075                block->block_contents_size - offset);
6076         switch(data->datatype)
6077         {
6078         case TNG_FLOAT_DATA:
6079             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
6080                data->codec_id == TNG_TNG_COMPRESSION)
6081             {
6082                 if(tng_data->input_endianness_swap_func_32)
6083                 {
6084                     for(i = offset; i < block->block_contents_size; i+=size)
6085                     {
6086                         if(tng_data->input_endianness_swap_func_32(tng_data,
6087                            (int32_t *)(block->block_contents + i))
6088                            != TNG_SUCCESS)
6089                         {
6090                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6091                                     __FILE__, __LINE__);
6092                         }
6093                     }
6094                 }
6095             }
6096             else
6097             {
6098                 multiplier = data->compression_multiplier;
6099                 if(fabs(multiplier - 1.0) > 0.00001 ||
6100                    tng_data->input_endianness_swap_func_32)
6101                 {
6102                     for(i = offset; block->block_contents_size; i+=size)
6103                     {
6104                         *(float *)(block->block_contents + i) *= (float)multiplier;
6105                         if(tng_data->input_endianness_swap_func_32 &&
6106                         tng_data->input_endianness_swap_func_32(tng_data,
6107                         (int32_t *)(block->block_contents + i))
6108                         != TNG_SUCCESS)
6109                         {
6110                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6111                                     __FILE__, __LINE__);
6112                         }
6113                     }
6114                 }
6115             }
6116             break;
6117         case TNG_INT_DATA:
6118             if(tng_data->input_endianness_swap_func_64)
6119             {
6120                 for(i = offset; i < block->block_contents_size; i+=size)
6121                 {
6122                     if(tng_data->input_endianness_swap_func_64(tng_data,
6123                        (int64_t *)(block->block_contents + i))
6124                        != TNG_SUCCESS)
6125                     {
6126                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6127                                 __FILE__, __LINE__);
6128                     }
6129                 }
6130             }
6131             break;
6132         case TNG_DOUBLE_DATA:
6133             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
6134                data->codec_id == TNG_TNG_COMPRESSION)
6135             {
6136                 if(tng_data->input_endianness_swap_func_64)
6137                 {
6138                     for(i = offset; i < block->block_contents_size; i+=size)
6139                     {
6140                         if(tng_data->input_endianness_swap_func_64(tng_data,
6141                            (int64_t *)(block->block_contents + i))
6142                            != TNG_SUCCESS)
6143                         {
6144                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6145                                     __FILE__, __LINE__);
6146                         }
6147                     }
6148                 }
6149             }
6150             else
6151             {
6152                 multiplier = data->compression_multiplier;
6153                 if(fabs(multiplier - 1.0) > 0.00001 ||
6154                    tng_data->input_endianness_swap_func_64)
6155                 {
6156                     for(i = offset; i < block->block_contents_size; i+=size)
6157                     {
6158                         *(double *)(block->block_contents + i) *= multiplier;
6159                         if(tng_data->input_endianness_swap_func_64 &&
6160                         tng_data->input_endianness_swap_func_64(tng_data,
6161                         (int64_t *)(block->block_contents + i))
6162                         != TNG_SUCCESS)
6163                         {
6164                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6165                                     __FILE__, __LINE__);
6166                         }
6167                     }
6168                 }
6169             }
6170             break;
6171         case TNG_CHAR_DATA:
6172             break;
6173         }
6174     }
6175     else
6176     {
6177         memset(block->block_contents+offset, 0, block->block_contents_size - offset);
6178     }
6179
6180     frame_set->n_written_frames += frame_set->n_unwritten_frames;
6181     frame_set->n_unwritten_frames = 0;
6182
6183     if(block_type_flag == TNG_NON_TRAJECTORY_BLOCK || frame_set->n_written_frames > 0)
6184     {
6185         switch(data->codec_id)
6186         {
6187 #ifdef USE_ZLIB
6188         case TNG_GZIP_COMPRESSION:
6189     /*         fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size); */
6190             stat = tng_gzip_compress(tng_data, block,
6191                                      block->block_contents + data_start_pos,
6192                                      block->block_contents_size - data_start_pos);
6193             if(stat != TNG_SUCCESS)
6194             {
6195                 fprintf(stderr, "TNG library: Could not write gzipped block data. %s: %d\n", __FILE__,
6196                     __LINE__);
6197                 if(stat == TNG_CRITICAL)
6198                 {
6199                     return(TNG_CRITICAL);
6200                 }
6201                 data->codec_id = TNG_UNCOMPRESSED;
6202             }
6203     /*         fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size); */
6204             break;
6205 #endif
6206         }
6207     }
6208
6209     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
6210     {
6211         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
6212                tng_data->output_file_path, __FILE__, __LINE__);
6213         return(TNG_CRITICAL);
6214     }
6215
6216     if(fwrite(block->block_contents, block->block_contents_size, 1,
6217               tng_data->output_file) != 1)
6218     {
6219         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n",
6220                __FILE__, __LINE__);
6221         return(TNG_CRITICAL);
6222     }
6223
6224     return(TNG_SUCCESS);
6225 }
6226
6227 /** Read the meta information of a data block (particle or non-particle data).
6228  * @param tng_data is a trajectory data container.
6229  * @param block is the block to store the data (should already contain
6230  * the block headers).
6231  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6232  * error has occured.
6233  */
6234 static tng_function_status tng_data_block_meta_information_read
6235                 (tng_trajectory_t tng_data,
6236                  tng_gen_block_t block,
6237                  int *offset,
6238                  char *datatype,
6239                  char *dependency,
6240                  char *sparse_data,
6241                  int64_t *n_values,
6242                  int64_t *codec_id,
6243                  int64_t *first_frame_with_data,
6244                  int64_t *stride_length,
6245                  int64_t *n_frames,
6246                  int64_t *num_first_particle,
6247                  int64_t *block_n_particles,
6248                  double *multiplier)
6249 {
6250     int meta_size;
6251     char *contents;
6252
6253     if(block->block_contents)
6254     {
6255         contents = block->block_contents;
6256     }
6257     else
6258     {
6259         meta_size = 3 * sizeof(char) + sizeof(double) + 6 * sizeof(int64_t);
6260         contents = malloc(meta_size);
6261         if(!contents)
6262         {
6263             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
6264                meta_size, __FILE__, __LINE__);
6265         }
6266
6267         if(fread(contents, meta_size, 1, tng_data->input_file) == 0)
6268         {
6269             fprintf(stderr, "TNG library: Cannot read data block meta information. %s: %d\n", __FILE__, __LINE__);
6270             free(contents);
6271             return(TNG_CRITICAL);
6272         }
6273     }
6274
6275     memcpy(datatype, contents+*offset,
6276            sizeof(*datatype));
6277     *offset += sizeof(*datatype);
6278
6279     memcpy(dependency, contents+*offset,
6280            sizeof(*dependency));
6281     *offset += sizeof(*dependency);
6282
6283     if(*dependency & TNG_FRAME_DEPENDENT)
6284     {
6285         memcpy(sparse_data, contents+*offset,
6286                sizeof(*sparse_data));
6287         *offset += sizeof(*sparse_data);
6288     }
6289
6290     memcpy(n_values, contents+*offset,
6291         sizeof(*n_values));
6292     if(tng_data->input_endianness_swap_func_64)
6293     {
6294         if(tng_data->input_endianness_swap_func_64(tng_data,
6295                                                    n_values)
6296             != TNG_SUCCESS)
6297         {
6298             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6299                     __FILE__, __LINE__);
6300         }
6301     }
6302     *offset += sizeof(*n_values);
6303
6304     memcpy(codec_id, contents+*offset,
6305         sizeof(*codec_id));
6306     if(tng_data->input_endianness_swap_func_64)
6307     {
6308         if(tng_data->input_endianness_swap_func_64(tng_data,
6309                                                    codec_id)
6310             != TNG_SUCCESS)
6311         {
6312             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6313                     __FILE__, __LINE__);
6314         }
6315     }
6316     *offset += sizeof(*codec_id);
6317
6318     if(*codec_id != TNG_UNCOMPRESSED)
6319     {
6320         memcpy(multiplier, contents+*offset,
6321             sizeof(*multiplier));
6322         if(tng_data->input_endianness_swap_func_64)
6323         {
6324             if(tng_data->input_endianness_swap_func_64(tng_data,
6325                                                        (int64_t *) multiplier)
6326                 != TNG_SUCCESS)
6327             {
6328                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6329                         __FILE__, __LINE__);
6330             }
6331         }
6332         *offset += sizeof(*multiplier);
6333     }
6334     else
6335     {
6336         *multiplier = 1;
6337     }
6338
6339     if(*dependency & TNG_FRAME_DEPENDENT)
6340     {
6341         if(*sparse_data)
6342         {
6343             memcpy(first_frame_with_data, contents+*offset,
6344                 sizeof(*first_frame_with_data));
6345             if(tng_data->input_endianness_swap_func_64)
6346             {
6347                 if(tng_data->input_endianness_swap_func_64(tng_data,
6348                                                            first_frame_with_data)
6349                     != TNG_SUCCESS)
6350                 {
6351                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6352                             __FILE__, __LINE__);
6353                 }
6354             }
6355             *offset += sizeof(*first_frame_with_data);
6356
6357             memcpy(stride_length, contents+*offset,
6358                 sizeof(*stride_length));
6359             if(tng_data->input_endianness_swap_func_64)
6360             {
6361                 if(tng_data->input_endianness_swap_func_64(tng_data,
6362                                                            stride_length)
6363                     != TNG_SUCCESS)
6364                 {
6365                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6366                             __FILE__, __LINE__);
6367                 }
6368             }
6369             *offset += sizeof(*stride_length);
6370             *n_frames = tng_data->current_trajectory_frame_set.n_frames -
6371                         (*first_frame_with_data -
6372                         tng_data->current_trajectory_frame_set.first_frame);
6373         }
6374         else
6375         {
6376             *first_frame_with_data = 0;
6377             *stride_length = 1;
6378             *n_frames = tng_data->current_trajectory_frame_set.n_frames;
6379         }
6380     }
6381     else
6382     {
6383         *first_frame_with_data = 0;
6384         *stride_length = 1;
6385         *n_frames = 1;
6386     }
6387
6388     if (*dependency & TNG_PARTICLE_DEPENDENT)
6389     {
6390         memcpy(num_first_particle, contents+*offset,
6391                sizeof(*num_first_particle));
6392         if(tng_data->input_endianness_swap_func_64)
6393         {
6394             if(tng_data->input_endianness_swap_func_64(tng_data,
6395                                                        num_first_particle)
6396                 != TNG_SUCCESS)
6397             {
6398                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6399                         __FILE__, __LINE__);
6400             }
6401         }
6402         *offset += sizeof(*num_first_particle);
6403
6404         memcpy(block_n_particles, contents+*offset,
6405             sizeof(*block_n_particles));
6406         if(tng_data->input_endianness_swap_func_64)
6407         {
6408             if(tng_data->input_endianness_swap_func_64(tng_data,
6409                                                        block_n_particles)
6410                 != TNG_SUCCESS)
6411             {
6412                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6413                         __FILE__, __LINE__);
6414             }
6415         }
6416         *offset += sizeof(*block_n_particles);
6417     }
6418
6419     if(!block->block_contents)
6420     {
6421         free(contents);
6422     }
6423     return(TNG_SUCCESS);
6424 }
6425
6426 /** Read the contents of a data block (particle or non-particle data).
6427  * @param tng_data is a trajectory data container.
6428  * @param block is the block to store the data (should already contain
6429  * the block headers).
6430  * @param hash_mode is an option to decide whether to use the md5 hash or not.
6431  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
6432  * compared to the md5 hash of the read contents to ensure valid data.
6433  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6434  * error has occured.
6435  */
6436 static tng_function_status tng_data_block_contents_read
6437                 (tng_trajectory_t tng_data,
6438                  tng_gen_block_t block,
6439                  const char hash_mode)
6440 {
6441     int64_t n_values, codec_id, n_frames, first_frame_with_data;
6442     int64_t stride_length, block_n_particles, num_first_particle;
6443     double multiplier;
6444     char datatype, dependency, sparse_data;
6445     int offset = 0;
6446     tng_bool same_hash;
6447
6448     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
6449     {
6450         return(TNG_CRITICAL);
6451     }
6452
6453     if(block->block_contents)
6454     {
6455         free(block->block_contents);
6456     }
6457
6458     block->block_contents = malloc(block->block_contents_size);
6459     if(!block->block_contents)
6460     {
6461         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
6462                block->block_contents_size, __FILE__, __LINE__);
6463         return(TNG_CRITICAL);
6464     }
6465
6466     /* Read the whole block into block_contents to be able to write it to
6467      * disk even if it cannot be interpreted. */
6468     if(fread(block->block_contents, block->block_contents_size, 1,
6469              tng_data->input_file) == 0)
6470     {
6471         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
6472         return(TNG_CRITICAL);
6473     }
6474
6475     /* FIXME: Does not check if the size of the contents matches the expected
6476      * size or if the contents can be read. */
6477
6478     if(hash_mode == TNG_USE_HASH)
6479     {
6480         tng_md5_hash_match_verify(block, &same_hash);
6481         if(same_hash != TNG_TRUE)
6482         {
6483             fprintf(stderr, "TNG library: '%s' data block contents corrupt. Hashes do not match. %s: %d\n",
6484                 block->name, __FILE__, __LINE__);
6485     /*         return(TNG_FAILURE); */
6486         }
6487     }
6488
6489     if(tng_data_block_meta_information_read(tng_data, block,
6490                                             &offset, &datatype,
6491                                             &dependency, &sparse_data,
6492                                             &n_values, &codec_id,
6493                                             &first_frame_with_data,
6494                                             &stride_length, &n_frames,
6495                                             &num_first_particle,
6496                                             &block_n_particles,
6497                                             &multiplier) == TNG_CRITICAL)
6498     {
6499         fprintf(stderr, "TNG library: Cannot read data block (%s) meta information. %s: %d\n",
6500             block->name, __FILE__, __LINE__);
6501         return(TNG_CRITICAL);
6502     }
6503
6504     if (dependency & TNG_PARTICLE_DEPENDENT)
6505     {
6506         return(tng_particle_data_read(tng_data, block,
6507                                       &offset, datatype,
6508                                       num_first_particle,
6509                                       block_n_particles,
6510                                       first_frame_with_data,
6511                                       stride_length,
6512                                       n_frames, n_values,
6513                                       codec_id, multiplier));
6514     }
6515     else
6516     {
6517         return(tng_data_read(tng_data, block,
6518                              &offset, datatype,
6519                              first_frame_with_data,
6520                              stride_length,
6521                              n_frames, n_values,
6522                              codec_id, multiplier));
6523     }
6524 }
6525
6526 /** Update the md5 hash of a block already written to the file
6527  * @param tng_data is a trajectory data container.
6528  * @param block is the block, of which to update the md5 hash.
6529  * @param header_start_pos is the file position where the block header starts.
6530  * @param contents_start_pos is the file position where the block contents
6531  * start.
6532  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6533  * error has occured.
6534  */
6535 static tng_function_status tng_md5_hash_update(tng_trajectory_t tng_data,
6536                                                tng_gen_block_t block,
6537                                                const int64_t header_start_pos,
6538                                                const int64_t contents_start_pos)
6539 {
6540     if(block->block_contents)
6541     {
6542         free(block->block_contents);
6543     }
6544
6545     block->block_contents = malloc(block->block_contents_size);
6546     if(!block->block_contents)
6547     {
6548         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
6549                block->block_contents_size, __FILE__, __LINE__);
6550         return(TNG_CRITICAL);
6551     }
6552
6553     fseek(tng_data->output_file, (long)contents_start_pos, SEEK_SET);
6554     if(fread(block->block_contents, block->block_contents_size, 1,
6555             tng_data->output_file) == 0)
6556     {
6557         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
6558         return(TNG_CRITICAL);
6559     }
6560
6561     tng_block_md5_hash_generate(block);
6562
6563     fseek(tng_data->output_file, (long)header_start_pos + 3 * sizeof(int64_t),
6564           SEEK_SET);
6565     fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file);
6566
6567     return(TNG_SUCCESS);
6568 }
6569
6570 /** Update the frame set pointers in the file header (general info block),
6571  * already written to disk
6572  * @param tng_data is a trajectory data container.
6573  * @param hash_mode specifies whether to update the block md5 hash when
6574  * updating the pointers.
6575  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6576  * error has occured.
6577  */
6578 static tng_function_status tng_header_pointers_update
6579                 (tng_trajectory_t tng_data, const char hash_mode)
6580 {
6581     tng_gen_block_t block;
6582     FILE *temp = tng_data->input_file;
6583     int64_t output_file_pos, pos, contents_start_pos;
6584
6585     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
6586     {
6587         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
6588                __FILE__, __LINE__);
6589         return(TNG_CRITICAL);
6590     }
6591
6592     tng_data->input_file = tng_data->output_file;
6593
6594     tng_block_init(&block);
6595
6596     output_file_pos = ftell(tng_data->output_file);
6597     fseek(tng_data->output_file, 0, SEEK_SET);
6598
6599     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
6600     {
6601         fprintf(stderr, "TNG library: Cannot read general info header. %s: %d\n",
6602                __FILE__, __LINE__);
6603         tng_data->input_file = temp;
6604         tng_block_destroy(&block);
6605         return(TNG_CRITICAL);
6606     }
6607
6608     contents_start_pos = ftell(tng_data->output_file);
6609
6610     fseek(tng_data->output_file, (long)block->block_contents_size - 5 *
6611           sizeof(int64_t), SEEK_CUR);
6612
6613     tng_data->input_file = temp;
6614
6615     pos = tng_data->first_trajectory_frame_set_output_file_pos;
6616
6617     if(tng_data->input_endianness_swap_func_64)
6618     {
6619         if(tng_data->input_endianness_swap_func_64(tng_data,
6620                                                     &pos)
6621             != TNG_SUCCESS)
6622         {
6623             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6624                     __FILE__, __LINE__);
6625         }
6626     }
6627
6628     if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
6629     {
6630         tng_block_destroy(&block);
6631         return(TNG_CRITICAL);
6632     }
6633
6634     pos = tng_data->last_trajectory_frame_set_output_file_pos;
6635
6636     if(tng_data->input_endianness_swap_func_64)
6637     {
6638         if(tng_data->input_endianness_swap_func_64(tng_data,
6639                                                     &pos)
6640             != TNG_SUCCESS)
6641         {
6642             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6643                     __FILE__, __LINE__);
6644         }
6645     }
6646
6647     if(fwrite(&pos,
6648         sizeof(int64_t), 1, tng_data->output_file) != 1)
6649     {
6650         tng_block_destroy(&block);
6651         return(TNG_CRITICAL);
6652     }
6653
6654     if(hash_mode == TNG_USE_HASH)
6655     {
6656         tng_md5_hash_update(tng_data, block, 0, contents_start_pos);
6657     }
6658
6659     tng_block_destroy(&block);
6660
6661     fseek(tng_data->output_file, (long)output_file_pos, SEEK_SET);
6662
6663     return(TNG_SUCCESS);
6664 }
6665
6666 /** Update the frame set pointers in the current frame set block, already
6667  * written to disk. It also updates the pointers of the blocks pointing to
6668  * the current frame set block.
6669  * @param tng_data is a trajectory data container.
6670  * @param hash_mode specifies whether to update the block md5 hash when
6671  * updating the pointers.
6672  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6673  * error has occured.
6674  */
6675 static tng_function_status tng_frame_set_pointers_update
6676                 (tng_trajectory_t tng_data, const char hash_mode)
6677 {
6678     tng_gen_block_t block;
6679     tng_trajectory_frame_set_t frame_set;
6680     FILE *temp = tng_data->input_file;
6681     int64_t pos, output_file_pos, header_start_pos, contents_start_pos;
6682
6683     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
6684     {
6685         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
6686                __FILE__, __LINE__);
6687         return(TNG_CRITICAL);
6688     }
6689
6690     tng_block_init(&block);
6691     output_file_pos = ftell(tng_data->output_file);
6692
6693     tng_data->input_file = tng_data->output_file;
6694
6695     frame_set = &tng_data->current_trajectory_frame_set;
6696
6697     /* Update previous frame set */
6698     if(frame_set->prev_frame_set_file_pos != -1 &&
6699        frame_set->prev_frame_set_file_pos != 0)
6700     {
6701         fseek(tng_data->output_file, (long)frame_set->prev_frame_set_file_pos,
6702               SEEK_SET);
6703
6704         header_start_pos = frame_set->prev_frame_set_file_pos;
6705
6706         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
6707         {
6708             fprintf(stderr, "TNG library: Cannot read frame header. %s: %d\n",
6709                 __FILE__, __LINE__);
6710             tng_data->input_file = temp;
6711             tng_block_destroy(&block);
6712             return(TNG_CRITICAL);
6713         }
6714
6715         contents_start_pos = ftell(tng_data->output_file);
6716
6717         fseek(tng_data->output_file, (long)block->block_contents_size - (6 *
6718             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
6719
6720         pos = tng_data->current_trajectory_frame_set_output_file_pos;
6721
6722         if(tng_data->input_endianness_swap_func_64)
6723         {
6724             if(tng_data->input_endianness_swap_func_64(tng_data,
6725                                                         &pos)
6726                 != TNG_SUCCESS)
6727             {
6728                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6729                         __FILE__, __LINE__);
6730             }
6731         }
6732
6733         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
6734         {
6735             tng_data->input_file = temp;
6736             tng_block_destroy(&block);
6737             return(TNG_CRITICAL);
6738         }
6739
6740         if(hash_mode == TNG_USE_HASH)
6741         {
6742             tng_md5_hash_update(tng_data, block, header_start_pos,
6743                                 contents_start_pos);
6744         }
6745         fseek(tng_data->output_file, (long)output_file_pos, SEEK_SET);
6746     }
6747
6748     /* Update the frame set one medium stride step before */
6749     if(frame_set->medium_stride_prev_frame_set_file_pos != -1 &&
6750        frame_set->medium_stride_prev_frame_set_file_pos != 0)
6751     {
6752         fseek(tng_data->output_file,
6753               (long)frame_set->medium_stride_prev_frame_set_file_pos,
6754               SEEK_SET);
6755
6756         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
6757         {
6758             fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
6759                 __FILE__, __LINE__);
6760             tng_data->input_file = temp;
6761             tng_block_destroy(&block);
6762             return(TNG_CRITICAL);
6763         }
6764
6765         contents_start_pos = ftell(tng_data->output_file);
6766
6767         fseek(tng_data->output_file, (long)block->block_contents_size - (4 *
6768             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
6769
6770         pos = tng_data->current_trajectory_frame_set_output_file_pos;
6771
6772         if(tng_data->input_endianness_swap_func_64)
6773         {
6774             if(tng_data->input_endianness_swap_func_64(tng_data,
6775                                                         &pos)
6776                 != TNG_SUCCESS)
6777             {
6778                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6779                         __FILE__, __LINE__);
6780             }
6781         }
6782
6783         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
6784         {
6785             tng_data->input_file = temp;
6786             tng_block_destroy(&block);
6787             return(TNG_CRITICAL);
6788         }
6789
6790         if(hash_mode == TNG_USE_HASH)
6791         {
6792             tng_md5_hash_update(tng_data, block,
6793                                 frame_set->medium_stride_prev_frame_set_file_pos,
6794                                 contents_start_pos);
6795         }
6796     }
6797
6798     /* Update the frame set one long stride step before */
6799     if(frame_set->long_stride_prev_frame_set_file_pos != -1 &&
6800        frame_set->long_stride_prev_frame_set_file_pos != 0)
6801     {
6802         fseek(tng_data->output_file,
6803               (long)frame_set->long_stride_prev_frame_set_file_pos,
6804               SEEK_SET);
6805
6806         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
6807         {
6808             fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
6809                 __FILE__, __LINE__);
6810             tng_data->input_file = temp;
6811             tng_block_destroy(&block);
6812             return(TNG_CRITICAL);
6813         }
6814
6815         contents_start_pos = ftell(tng_data->output_file);
6816
6817         fseek(tng_data->output_file, (long)block->block_contents_size - (2 *
6818             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
6819
6820         pos = tng_data->current_trajectory_frame_set_output_file_pos;
6821
6822         if(tng_data->input_endianness_swap_func_64)
6823         {
6824             if(tng_data->input_endianness_swap_func_64(tng_data,
6825                                                         &pos)
6826                 != TNG_SUCCESS)
6827             {
6828                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6829                         __FILE__, __LINE__);
6830             }
6831         }
6832
6833         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
6834         {
6835             tng_data->input_file = temp;
6836             tng_block_destroy(&block);
6837             return(TNG_CRITICAL);
6838         }
6839
6840         if(hash_mode == TNG_USE_HASH)
6841         {
6842             tng_md5_hash_update(tng_data, block,
6843                                 frame_set->long_stride_prev_frame_set_file_pos,
6844                                 contents_start_pos);
6845         }
6846     }
6847
6848     fseek(tng_data->output_file, (long)output_file_pos, SEEK_SET);
6849
6850     tng_data->input_file = temp;
6851
6852     tng_block_destroy(&block);
6853
6854     return(TNG_SUCCESS);
6855 }
6856 /*
6857 // ** Move the blocks in a frame set so that there is no unused space between
6858 //  * them. This can only be done on the last frame set in the file and should
6859 //  * be done e.g. if the last frame set in the file has fewer frames than
6860 //  * default or after compressing data blocks in a frame set.
6861 //  * @param tng_data is a trajectory data container.
6862 //  * @details the current_trajectory_frame_set is the one that will be modified.
6863 //  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the frame set
6864 //  * cannot be aligned or TNG_CRITICAL (2) if a major error has occured.
6865 //  * FIXME: This function is not finished!!!
6866 //  *
6867 // static tng_function_status tng_frame_set_align(tng_trajectory_t tng_data)
6868 // {
6869 //     tng_gen_block_t block;
6870 //     tng_trajectory_frame_set_t frame_set;
6871 //     FILE *temp = tng_data->input_file;
6872 //     int64_t pos, contents_start_pos, output_file_len;
6873 //
6874 //     frame_set = &tng_data->current_trajectory_frame_set;
6875 //
6876 //     if(frame_set->n_written_frames == frame_set->n_frames)
6877 //     {
6878 //         return(TNG_SUCCESS);
6879 //     }
6880 //
6881 //     if(tng_data->current_trajectory_frame_set_output_file_pos !=
6882 //        tng_data->last_trajectory_frame_set_output_file_pos)
6883 //     {
6884 //     }
6885 //
6886 //     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
6887 //     {
6888 //         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
6889 //                __FILE__, __LINE__);
6890 //         return(TNG_CRITICAL);
6891 //     }
6892 //
6893 //     tng_block_init(&block);
6894 // //     output_file_pos = ftell(tng_data->output_file);
6895 //
6896 //     tng_data->input_file = tng_data->output_file;
6897 //
6898 //     pos = tng_data->current_trajectory_frame_set_output_file_pos;
6899 //
6900 //     fseek(tng_data->output_file, pos, SEEK_SET);
6901 //     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
6902 //     {
6903 //         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
6904 //             __FILE__, __LINE__);
6905 //         tng_data->input_file = temp;
6906 //         tng_block_destroy(&block);
6907 //         return(TNG_CRITICAL);
6908 //     }
6909 //
6910 //     contents_start_pos = ftell(tng_data->output_file);
6911 //
6912 //     fseek(tng_data->output_file, 0, SEEK_END);
6913 //     output_file_len = ftell(tng_data->output_file);
6914 //     pos = contents_start_pos + block->block_contents_size;
6915 //     fseek(tng_data->output_file, pos,
6916 //           SEEK_SET);
6917 //
6918 //     while(pos < output_file_len)
6919 //     {
6920 //         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
6921 //         {
6922 //             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", pos,
6923 //                    __FILE__, __LINE__);
6924 //             tng_data->input_file = temp;
6925 //             tng_block_destroy(&block);
6926 //             return(TNG_CRITICAL);
6927 //         }
6928 //         pos += block->header_contents_size + block->block_contents_size;
6929 //         fseek(tng_data->output_file, pos, SEEK_SET);
6930 //     }
6931 //
6932 //     return(TNG_SUCCESS);
6933 // }
6934 */
6935 /** Finish writing the current frame set. Update the number of frames
6936  * and the hashes of the frame set and all its data blocks (if hash_mode
6937  * == TNG_USE_HASH).
6938  * @param tng_data is a trajectory data container.
6939  * @param hash_mode specifies whether to update the block md5 hash when
6940  * updating the pointers.
6941  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6942  * error has occured.
6943  */
6944 static tng_function_status tng_frame_set_finalize
6945                 (tng_trajectory_t tng_data, const char hash_mode)
6946 {
6947     tng_gen_block_t block;
6948     tng_trajectory_frame_set_t frame_set;
6949     FILE *temp = tng_data->input_file;
6950     int64_t pos, contents_start_pos, output_file_len;
6951
6952     frame_set = &tng_data->current_trajectory_frame_set;
6953
6954     if(frame_set->n_written_frames == frame_set->n_frames)
6955     {
6956         return(TNG_SUCCESS);
6957     }
6958
6959     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
6960     {
6961         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
6962                __FILE__, __LINE__);
6963         return(TNG_CRITICAL);
6964     }
6965
6966     tng_block_init(&block);
6967 /*     output_file_pos = ftell(tng_data->output_file); */
6968
6969     tng_data->input_file = tng_data->output_file;
6970
6971     pos = tng_data->current_trajectory_frame_set_output_file_pos;
6972
6973     fseek(tng_data->output_file, (long)pos, SEEK_SET);
6974
6975     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
6976     {
6977         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
6978             __FILE__, __LINE__);
6979         tng_data->input_file = temp;
6980         tng_block_destroy(&block);
6981         return(TNG_CRITICAL);
6982     }
6983
6984     contents_start_pos = ftell(tng_data->output_file);
6985
6986     fseek(tng_data->output_file, sizeof(frame_set->first_frame), SEEK_CUR);
6987     if(fwrite(&frame_set->n_written_frames, sizeof(frame_set->n_frames),
6988               1, tng_data->output_file) != 1)
6989     {
6990         tng_data->input_file = temp;
6991         tng_block_destroy(&block);
6992         return(TNG_CRITICAL);
6993     }
6994
6995
6996     if(hash_mode == TNG_USE_HASH)
6997     {
6998         tng_md5_hash_update(tng_data, block, pos,
6999                             pos + block->header_contents_size);
7000     }
7001
7002     fseek(tng_data->output_file, 0, SEEK_END);
7003     output_file_len = ftell(tng_data->output_file);
7004     pos = contents_start_pos + block->block_contents_size;
7005     fseek(tng_data->output_file, (long)pos, SEEK_SET);
7006
7007     while(pos < output_file_len)
7008     {
7009         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
7010         {
7011             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", pos,
7012                    __FILE__, __LINE__);
7013             tng_data->input_file = temp;
7014             tng_block_destroy(&block);
7015             return(TNG_CRITICAL);
7016         }
7017
7018         if(hash_mode == TNG_USE_HASH)
7019         {
7020             tng_md5_hash_update(tng_data, block, pos,
7021                                 pos + block->header_contents_size);
7022         }
7023         pos += block->header_contents_size + block->block_contents_size;
7024         fseek(tng_data->output_file, (long)pos, SEEK_SET);
7025     }
7026
7027     tng_data->input_file = temp;
7028     tng_block_destroy(&block);
7029     return(TNG_SUCCESS);
7030 }
7031
7032 /*
7033 // ** Sets the name of a file contents block
7034 //  * @param tng_data is a trajectory data container.
7035 //  * @param block is the block, of which to change names.
7036 //  * @param new_name is the new name of the block.
7037 //  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
7038 //  * error has occured.
7039 //
7040 // static tng_function_status tng_block_name_set(tng_trajectory_t tng_data,
7041 //                                               tng_gen_block_t block,
7042 //                                               const char *new_name)
7043 // {
7044 //     int len;
7045 //
7046 //     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
7047 //
7048 //      * If the currently stored string length is not enough to store the new
7049 //      * string it is freed and reallocated. *
7050 //     if(block->name && strlen(block->name) < len)
7051 //     {
7052 //         free(block->name);
7053 //         block->name = 0;
7054 //     }
7055 //     if(!block->name)
7056 //     {
7057 //         block->name = malloc(len);
7058 //         if(!block->name)
7059 //         {
7060 //             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
7061 //                    __FILE__, __LINE__);
7062 //             return(TNG_CRITICAL);
7063 //         }
7064 //     }
7065 //
7066 //     strncpy(block->name, new_name, len);
7067 //
7068 //     return(TNG_SUCCESS);
7069 // }
7070 */
7071
7072 tng_function_status tng_atom_residue_get(const tng_trajectory_t tng_data,
7073                                          const tng_atom_t atom,
7074                                          tng_residue_t *residue)
7075 {
7076     (void) tng_data;
7077
7078     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
7079
7080     *residue = atom->residue;
7081
7082     return(TNG_SUCCESS);
7083 }
7084
7085 tng_function_status tng_atom_name_get(const tng_trajectory_t tng_data,
7086                                       const tng_atom_t atom,
7087                                       char *name,
7088                                       const int max_len)
7089 {
7090     (void) tng_data;
7091     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
7092     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
7093
7094     strncpy(name, atom->name, max_len - 1);
7095     name[max_len - 1] = 0;
7096
7097     if(strlen(atom->name) > (unsigned int)max_len - 1)
7098     {
7099         return(TNG_FAILURE);
7100     }
7101     return(TNG_SUCCESS);
7102 }
7103
7104 tng_function_status tng_atom_name_set(tng_trajectory_t tng_data,
7105                                       tng_atom_t atom,
7106                                       const char *new_name)
7107 {
7108     unsigned int len;
7109     (void)tng_data;
7110
7111     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7112     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
7113
7114     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
7115
7116     /* If the currently stored string length is not enough to store the new
7117      * string it is freed and reallocated. */
7118     if(atom->name && strlen(atom->name) < len)
7119     {
7120         free(atom->name);
7121         atom->name = 0;
7122     }
7123     if(!atom->name)
7124     {
7125         atom->name = malloc(len);
7126         if(!atom->name)
7127         {
7128             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
7129                    __FILE__, __LINE__);
7130             return(TNG_CRITICAL);
7131         }
7132     }
7133
7134     strncpy(atom->name, new_name, len);
7135
7136     return(TNG_SUCCESS);
7137 }
7138
7139 tng_function_status tng_atom_type_get(const tng_trajectory_t tng_data,
7140                                       const tng_atom_t atom,
7141                                       char *type,
7142                                       const int max_len)
7143 {
7144     (void) tng_data;
7145     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
7146     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer");
7147
7148     strncpy(type, atom->atom_type, max_len - 1);
7149     type[max_len - 1] = 0;
7150
7151     if(strlen(atom->atom_type) > (unsigned int)max_len - 1)
7152     {
7153         return(TNG_FAILURE);
7154     }
7155     return(TNG_SUCCESS);
7156 }
7157
7158 tng_function_status tng_atom_type_set(tng_trajectory_t tng_data,
7159                                       tng_atom_t atom,
7160                                       const char *new_type)
7161 {
7162     unsigned int len;
7163     (void)tng_data;
7164
7165     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7166     TNG_ASSERT(new_type, "TNG library: new_type must not be a NULL pointer.");
7167
7168     len = tng_min_i((int)strlen(new_type) + 1, TNG_MAX_STR_LEN);
7169
7170     /* If the currently stored string length is not enough to store the new
7171      * string it is freed and reallocated. */
7172     if(atom->atom_type && strlen(atom->atom_type) < len)
7173     {
7174         free(atom->atom_type);
7175         atom->atom_type = 0;
7176     }
7177     if(!atom->atom_type)
7178     {
7179         atom->atom_type = malloc(len);
7180         if(!atom->atom_type)
7181         {
7182             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
7183                    __FILE__, __LINE__);
7184             return(TNG_CRITICAL);
7185         }
7186     }
7187
7188     strncpy(atom->atom_type, new_type, len);
7189
7190     return(TNG_SUCCESS);
7191 }
7192
7193 /** Initialise an atom struct
7194  * @param atom is the atom to initialise.
7195  * @return TNG_SUCCESS (0) if successful.
7196  */
7197 static tng_function_status tng_atom_init(tng_atom_t atom)
7198 {
7199     atom->name = 0;
7200     atom->atom_type = 0;
7201
7202     return(TNG_SUCCESS);
7203 }
7204
7205 /** Free the memory in an atom struct
7206  * @param atom is the atom to destroy.
7207  * @return TNG_SUCCESS (0) if successful.
7208  */
7209 static tng_function_status tng_atom_destroy(tng_atom_t atom)
7210 {
7211     if(atom->name)
7212     {
7213         free(atom->name);
7214         atom->name = 0;
7215     }
7216     if(atom->atom_type)
7217     {
7218         free(atom->atom_type);
7219         atom->atom_type = 0;
7220     }
7221
7222     return(TNG_SUCCESS);
7223 }
7224
7225 tng_function_status DECLSPECDLLEXPORT tng_molecule_add
7226                 (tng_trajectory_t tng_data,
7227                  const char *name,
7228                  tng_molecule_t *molecule)
7229 {
7230     int64_t id, i;
7231     tng_bool found_id = TNG_TRUE;
7232
7233     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7234     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7235
7236     /* Find an unused ID */
7237     id = 0;
7238     while(found_id)
7239     {
7240         found_id = TNG_FALSE;
7241         for(i = tng_data->n_molecules; i--;)
7242         {
7243             if(tng_data->molecules[i].id == id)
7244             {
7245                 found_id = TNG_TRUE;
7246                 i = 0;
7247             }
7248         }
7249         if(found_id)
7250         {
7251             id++;
7252         }
7253     }
7254
7255     return(tng_molecule_w_id_add(tng_data, name, id, molecule));
7256 }
7257
7258 tng_function_status DECLSPECDLLEXPORT tng_molecule_w_id_add
7259                 (tng_trajectory_t tng_data,
7260                  const char *name,
7261                  const int64_t id,
7262                  tng_molecule_t *molecule)
7263 {
7264     tng_molecule_t new_molecules;
7265     int64_t *new_molecule_cnt_list, i;
7266     tng_function_status stat = TNG_SUCCESS;
7267
7268     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7269     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7270
7271     new_molecules = realloc(tng_data->molecules,
7272                             sizeof(struct tng_molecule) *
7273                             (tng_data->n_molecules + 1));
7274
7275     if(!new_molecules)
7276     {
7277         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7278                sizeof(struct tng_molecule) * (tng_data->n_molecules + 1),
7279                __FILE__, __LINE__);
7280         free(tng_data->molecules);
7281         tng_data->molecules = 0;
7282         return(TNG_CRITICAL);
7283     }
7284
7285     new_molecule_cnt_list = realloc(tng_data->molecule_cnt_list,
7286                                     sizeof(int64_t) *
7287                                     (tng_data->n_molecules + 1));
7288
7289     if(!new_molecule_cnt_list)
7290     {
7291         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7292                sizeof(int64_t) * (tng_data->n_molecules + 1),
7293                __FILE__, __LINE__);
7294         free(tng_data->molecule_cnt_list);
7295         tng_data->molecule_cnt_list = 0;
7296         free(new_molecules);
7297         return(TNG_CRITICAL);
7298     }
7299
7300     tng_data->molecules = new_molecules;
7301     tng_data->molecule_cnt_list = new_molecule_cnt_list;
7302
7303     *molecule = &new_molecules[tng_data->n_molecules];
7304
7305     tng_molecule_init(tng_data, *molecule);
7306     tng_molecule_name_set(tng_data, *molecule, name);
7307
7308     /* FIXME: Should this be a function argument instead? */
7309     tng_data->molecule_cnt_list[tng_data->n_molecules] = 0;
7310
7311     for(i = tng_data->n_molecules; i--;)
7312     {
7313         if(tng_data->molecules[i].id == id)
7314         {
7315             stat = TNG_FAILURE;
7316             fprintf(stderr, "TNG library: Molecule ID %"PRId64" already in use. %s: %d\n", id,
7317                    __FILE__, __LINE__);
7318             break;
7319         }
7320     }
7321
7322     (*molecule)->id = id;
7323
7324     tng_data->n_molecules++;
7325
7326     return(stat);
7327 }
7328
7329 tng_function_status DECLSPECDLLEXPORT tng_molecule_existing_add
7330                 (tng_trajectory_t tng_data,
7331                  tng_molecule_t *molecule_p)
7332 {
7333     tng_bool found_id = TNG_TRUE;
7334     tng_molecule_t new_molecules, molecule;
7335     int64_t *new_molecule_cnt_list, i, id;
7336
7337     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7338
7339     /* Find an unused ID */
7340     id = 0;
7341     while(found_id)
7342     {
7343         found_id = TNG_FALSE;
7344         for(i = tng_data->n_molecules; i--;)
7345         {
7346             if(tng_data->molecules[i].id == id)
7347             {
7348                 found_id = TNG_TRUE;
7349                 i = 0;
7350             }
7351         }
7352         if(found_id)
7353         {
7354             id++;
7355         }
7356     }
7357
7358     new_molecules = realloc(tng_data->molecules,
7359                             sizeof(struct tng_molecule) *
7360                             (tng_data->n_molecules + 1));
7361
7362     if(!new_molecules)
7363     {
7364         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7365                sizeof(struct tng_molecule) * (tng_data->n_molecules + 1),
7366                __FILE__, __LINE__);
7367         free(tng_data->molecules);
7368         tng_data->molecules = 0;
7369         return(TNG_CRITICAL);
7370     }
7371
7372     new_molecule_cnt_list = realloc(tng_data->molecule_cnt_list,
7373                                     sizeof(int64_t) *
7374                                     (tng_data->n_molecules + 1));
7375
7376     if(!new_molecule_cnt_list)
7377     {
7378         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7379                sizeof(int64_t) * (tng_data->n_molecules + 1),
7380                __FILE__, __LINE__);
7381         free(tng_data->molecule_cnt_list);
7382         tng_data->molecule_cnt_list = 0;
7383         free(new_molecules);
7384         return(TNG_CRITICAL);
7385     }
7386
7387     molecule = *molecule_p;
7388
7389     tng_data->molecules = new_molecules;
7390     tng_data->molecule_cnt_list = new_molecule_cnt_list;
7391
7392     new_molecules[tng_data->n_molecules] = *molecule;
7393
7394     tng_data->molecule_cnt_list[tng_data->n_molecules] = 0;
7395
7396     free(*molecule_p);
7397
7398     molecule = &new_molecules[tng_data->n_molecules];
7399
7400     *molecule_p = molecule;
7401
7402     molecule->id = id;
7403
7404     tng_data->n_molecules++;
7405
7406     return(TNG_SUCCESS);
7407 }
7408
7409 tng_function_status tng_molecule_name_get(const tng_trajectory_t tng_data,
7410                                           const tng_molecule_t molecule,
7411                                           char *name,
7412                                           const int max_len)
7413 {
7414     (void) tng_data;
7415     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
7416     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
7417
7418     strncpy(name, molecule->name, max_len - 1);
7419     name[max_len - 1] = 0;
7420
7421     if(strlen(molecule->name) > (unsigned int)max_len - 1)
7422     {
7423         return(TNG_FAILURE);
7424     }
7425     return(TNG_SUCCESS);
7426 }
7427
7428 tng_function_status DECLSPECDLLEXPORT tng_molecule_name_set
7429                 (tng_trajectory_t tng_data,
7430                  tng_molecule_t molecule,
7431                  const char *new_name)
7432 {
7433     unsigned int len;
7434     (void)tng_data;
7435
7436     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7437     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
7438
7439     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
7440
7441     /* If the currently stored string length is not enough to store the new
7442      * string it is freed and reallocated. */
7443     if(molecule->name && strlen(molecule->name) < len)
7444     {
7445         free(molecule->name);
7446         molecule->name = 0;
7447     }
7448     if(!molecule->name)
7449     {
7450         molecule->name = malloc(len);
7451         if(!molecule->name)
7452         {
7453             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
7454                    __FILE__, __LINE__);
7455             return(TNG_CRITICAL);
7456         }
7457     }
7458
7459     strncpy(molecule->name, new_name, len);
7460
7461     return(TNG_SUCCESS);
7462 }
7463
7464 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_get
7465                 (const tng_trajectory_t tng_data,
7466                  const tng_molecule_t molecule,
7467                  int64_t *cnt)
7468 {
7469     int64_t i, index = -1;
7470
7471     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7472     TNG_ASSERT(cnt, "TNG library: cnt must not be a NULL pointer.");
7473
7474     for(i = tng_data->n_molecules; i--;)
7475     {
7476         if(&tng_data->molecules[i] == molecule)
7477         {
7478             index = i;
7479             i = 0;
7480         }
7481     }
7482     if(index == -1)
7483     {
7484         return(TNG_FAILURE);
7485     }
7486     *cnt = tng_data->molecule_cnt_list[index];
7487
7488     return(TNG_SUCCESS);
7489 }
7490
7491 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_set
7492                 (tng_trajectory_t tng_data,
7493                  tng_molecule_t molecule,
7494                  const int64_t cnt)
7495 {
7496     int64_t i, old_cnt, index = -1;
7497
7498     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7499
7500     for(i = tng_data->n_molecules; i--;)
7501     {
7502         if(&tng_data->molecules[i] == molecule)
7503         {
7504             index = i;
7505             i = 0;
7506         }
7507     }
7508     if(index == -1)
7509     {
7510         fprintf(stderr, "TNG library: Could not find molecule in TNG trajectory. %s: %d\n",
7511                __FILE__, __LINE__);
7512         return(TNG_FAILURE);
7513     }
7514     if(tng_data->var_num_atoms_flag == TNG_CONSTANT_N_ATOMS)
7515     {
7516         old_cnt = tng_data->molecule_cnt_list[index];
7517         tng_data->molecule_cnt_list[index] = cnt;
7518
7519         tng_data->n_particles += (cnt-old_cnt) *
7520                                  tng_data->molecules[index].n_atoms;
7521     }
7522     else
7523     {
7524         old_cnt = tng_data->current_trajectory_frame_set.molecule_cnt_list[index];
7525         tng_data->current_trajectory_frame_set.molecule_cnt_list[index] = cnt;
7526
7527         tng_data->current_trajectory_frame_set.n_particles += (cnt-old_cnt) *
7528                 tng_data->molecules[index].n_atoms;
7529     }
7530
7531     return(TNG_SUCCESS);
7532 }
7533
7534 tng_function_status DECLSPECDLLEXPORT tng_molecule_find
7535                 (tng_trajectory_t tng_data,
7536                  const char *name,
7537                  int64_t nr,
7538                  tng_molecule_t *molecule)
7539 {
7540     int64_t i, n_molecules;
7541
7542     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7543     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7544     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7545
7546     n_molecules = tng_data->n_molecules;
7547
7548     for(i = 0; i < n_molecules; i++)
7549     {
7550         *molecule = &tng_data->molecules[i];
7551         if(name[0] == 0 || strcmp(name, (*molecule)->name) == 0)
7552         {
7553             if(nr == -1 || nr == (*molecule)->id)
7554             {
7555                 return(TNG_SUCCESS);
7556             }
7557         }
7558     }
7559
7560     *molecule = 0;
7561
7562     return(TNG_FAILURE);
7563 }
7564
7565 tng_function_status DECLSPECDLLEXPORT tng_molecule_of_index_get
7566                 (tng_trajectory_t tng_data,
7567                  int64_t index,
7568                  tng_molecule_t *molecule)
7569 {
7570     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7571     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7572
7573     if(index >= tng_data->n_molecules)
7574     {
7575         *molecule = 0;
7576         return(TNG_FAILURE);
7577     }
7578     *molecule = &tng_data->molecules[index];
7579     return(TNG_SUCCESS);
7580 }
7581
7582 tng_function_status DECLSPECDLLEXPORT tng_molecule_system_copy(tng_trajectory_t tng_data_src,
7583                                                                tng_trajectory_t tng_data_dest)
7584 {
7585     tng_molecule_t molecule, molecule_temp;
7586     tng_chain_t chain, chain_temp;
7587     tng_residue_t residue, residue_temp;
7588     tng_atom_t atom, atom_temp;
7589     tng_bond_t bond_temp;
7590     tng_function_status stat;
7591     int64_t i, j, k, l, *list_temp;
7592
7593     TNG_ASSERT(tng_data_src, "TNG library: Trajectory container not properly setup.");
7594     TNG_ASSERT(tng_data_dest, "TNG library: Trajectory container not properly setup.");
7595
7596     for(i = 0; i < tng_data_dest->n_molecules; i++)
7597     {
7598         molecule = &tng_data_dest->molecules[i];
7599         tng_molecule_destroy(tng_data_dest, molecule);
7600     }
7601
7602     tng_data_dest->n_molecules = 0;
7603     tng_data_dest->n_particles = 0;
7604
7605     molecule_temp = realloc(tng_data_dest->molecules,
7606                     sizeof(struct tng_molecule) * tng_data_src->n_molecules);
7607     if(!molecule_temp)
7608     {
7609         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7610                sizeof(struct tng_molecule) * tng_data_src->n_molecules,
7611                __FILE__, __LINE__);
7612         free(tng_data_dest->molecules);
7613         tng_data_dest->molecules = 0;
7614         return(TNG_CRITICAL);
7615     }
7616     list_temp = realloc(tng_data_dest->molecule_cnt_list,
7617                                      sizeof(int64_t) * tng_data_src->n_molecules);
7618     if(!list_temp)
7619     {
7620         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7621                sizeof(int64_t) * tng_data_src->n_molecules,
7622                __FILE__, __LINE__);
7623         free(tng_data_dest->molecule_cnt_list);
7624         tng_data_dest->molecule_cnt_list = 0;
7625         free(molecule_temp);
7626         return(TNG_CRITICAL);
7627     }
7628
7629     tng_data_dest->molecules = molecule_temp;
7630     tng_data_dest->molecule_cnt_list = list_temp;
7631
7632     for(i = 0; i < tng_data_src->n_molecules; i++)
7633     {
7634         molecule = &tng_data_src->molecules[i];
7635         stat = tng_molecule_w_id_add(tng_data_dest, molecule->name, molecule->id,
7636                                      &molecule_temp);
7637         if(stat != TNG_SUCCESS)
7638         {
7639             fprintf(stderr, "TNG library: Cannot create new molecule to make a copy. %s: %d\n",
7640                    __FILE__, __LINE__);
7641             return(stat);
7642         }
7643         molecule_temp->quaternary_str = molecule->quaternary_str;
7644         for(j = 0; j < molecule->n_chains; j++)
7645         {
7646             chain = &molecule->chains[j];
7647             stat = tng_molecule_chain_w_id_add(tng_data_dest, molecule_temp,
7648                                                chain->name, chain->id,
7649                                                &chain_temp);
7650             if(stat != TNG_SUCCESS)
7651             {
7652                 fprintf(stderr, "TNG library: Cannot create new chain to make a copy. %s: %d\n",
7653                        __FILE__, __LINE__);
7654                 return(stat);
7655             }
7656             for(k = 0; k < chain->n_residues; k++)
7657             {
7658                 residue = &chain->residues[k];
7659                 stat = tng_chain_residue_w_id_add(tng_data_dest, chain_temp,
7660                                                   residue->name, residue->id,
7661                                                   &residue_temp);
7662                 if(stat != TNG_SUCCESS)
7663                 {
7664                     fprintf(stderr, "TNG library: Cannot create new residue to make a copy. %s: %d\n",
7665                            __FILE__, __LINE__);
7666                     return(stat);
7667                 }
7668                 for(l = 0; l < residue->n_atoms; l++)
7669                 {
7670                     atom = &molecule->atoms[residue->atoms_offset + l];
7671                     stat = tng_residue_atom_w_id_add(tng_data_dest, residue_temp,
7672                                                      atom->name, atom->atom_type,
7673                                                      atom->id, &atom_temp);
7674                     if(stat != TNG_SUCCESS)
7675                     {
7676                     fprintf(stderr, "TNG library: Cannot create new atom to make a copy. %s: %d\n",
7677                            __FILE__, __LINE__);
7678                         return(stat);
7679                     }
7680                 }
7681             }
7682         }
7683         molecule_temp->n_bonds = molecule->n_bonds;
7684         bond_temp = realloc(molecule_temp->bonds, sizeof(struct tng_bond) *
7685                             molecule->n_bonds);
7686         if(!bond_temp)
7687         {
7688             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7689                    sizeof(struct tng_bond) * molecule->n_bonds,
7690                    __FILE__, __LINE__);
7691             free(molecule_temp->bonds);
7692             molecule_temp->n_bonds = 0;
7693             return(TNG_CRITICAL);
7694         }
7695         molecule_temp->bonds = bond_temp;
7696         for(j = 0; j < molecule->n_bonds; j++)
7697         {
7698             molecule_temp->bonds[j] = molecule->bonds[j];
7699         }
7700         stat = tng_molecule_cnt_set(tng_data_dest, molecule_temp,
7701                                     tng_data_src->molecule_cnt_list[i]);
7702         if(stat != TNG_SUCCESS)
7703         {
7704             fprintf(stderr, "TNG library: Cannot set molecule count. %s: %d.\n",
7705                    __FILE__, __LINE__);
7706             return(stat);
7707         }
7708     }
7709     return(TNG_SUCCESS);
7710 }
7711
7712 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_chains_get
7713                 (const tng_trajectory_t tng_data,
7714                  const tng_molecule_t molecule,
7715                  int64_t *n)
7716 {
7717     (void) tng_data;
7718     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
7719     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
7720
7721     *n = molecule->n_chains;
7722
7723     return(TNG_SUCCESS);
7724 }
7725
7726 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_of_index_get
7727                 (tng_trajectory_t tng_data,
7728                  tng_molecule_t molecule,
7729                  int64_t index,
7730                  tng_chain_t *chain)
7731 {
7732     (void) tng_data;
7733     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7734     TNG_ASSERT(chain, "TNG library: chain must not be a NULL pointer.");
7735
7736     if(index >= molecule->n_chains)
7737     {
7738         *chain = 0;
7739         return(TNG_FAILURE);
7740     }
7741     *chain = &molecule->chains[index];
7742     return(TNG_SUCCESS);
7743 }
7744
7745 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_residues_get
7746                 (const tng_trajectory_t tng_data,
7747                  const tng_molecule_t molecule,
7748                  int64_t *n)
7749 {
7750     (void) tng_data;
7751     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
7752     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
7753
7754     *n = molecule->n_residues;
7755
7756     return(TNG_SUCCESS);
7757 }
7758
7759 tng_function_status DECLSPECDLLEXPORT tng_molecule_residue_of_index_get
7760                 (const tng_trajectory_t tng_data,
7761                  const tng_molecule_t molecule,
7762                  const int64_t index,
7763                  tng_residue_t *residue)
7764 {
7765     (void) tng_data;
7766     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7767     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
7768
7769     if(index >= molecule->n_residues)
7770     {
7771         *residue = 0;
7772         return(TNG_FAILURE);
7773     }
7774     *residue = &molecule->residues[index];
7775     return(TNG_SUCCESS);
7776 }
7777
7778 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_atoms_get
7779                 (const tng_trajectory_t tng_data,
7780                  const tng_molecule_t molecule,
7781                  int64_t *n)
7782 {
7783     (void) tng_data;
7784     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
7785     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
7786
7787     *n = molecule->n_atoms;
7788
7789     return(TNG_SUCCESS);
7790 }
7791
7792 tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_of_index_get
7793                 (const tng_trajectory_t tng_data,
7794                  const tng_molecule_t molecule,
7795                  const int64_t index,
7796                  tng_atom_t *atom)
7797 {
7798     (void) tng_data;
7799     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7800     TNG_ASSERT(atom, "TNG library: atom must not be a NULL pointer.");
7801
7802     if(index >= molecule->n_atoms)
7803     {
7804         *atom = 0;
7805         return(TNG_FAILURE);
7806     }
7807     *atom = &molecule->atoms[index];
7808     return(TNG_SUCCESS);
7809 }
7810
7811 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_find
7812                 (tng_trajectory_t tng_data,
7813                  tng_molecule_t molecule,
7814                  const char *name,
7815                  int64_t nr,
7816                  tng_chain_t *chain)
7817 {
7818     int64_t i, n_chains;
7819     (void)tng_data;
7820
7821     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7822     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7823
7824     n_chains = molecule->n_chains;
7825
7826     for(i = 0; i < n_chains; i++)
7827     {
7828         *chain = &molecule->chains[i];
7829         if(name[0] == 0 || strcmp(name, (*chain)->name) == 0)
7830         {
7831             if(nr == -1 || nr == (*chain)->id)
7832             {
7833                 return(TNG_SUCCESS);
7834             }
7835         }
7836     }
7837
7838     *chain = 0;
7839
7840     return(TNG_FAILURE);
7841 }
7842
7843 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_add
7844                 (tng_trajectory_t tng_data,
7845                  tng_molecule_t molecule,
7846                  const char *name,
7847                  tng_chain_t *chain)
7848 {
7849     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7850     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7851
7852     return(tng_molecule_chain_w_id_add(tng_data, molecule, name,
7853                                        molecule->n_chains + 1, chain));
7854 }
7855
7856 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_w_id_add
7857                 (tng_trajectory_t tng_data,
7858                  tng_molecule_t molecule,
7859                  const char *name,
7860                  const int64_t id,
7861                  tng_chain_t *chain)
7862 {
7863     int64_t i;
7864     tng_chain_t new_chains;
7865     tng_function_status stat = TNG_SUCCESS;
7866
7867     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7868     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7869
7870     new_chains = realloc(molecule->chains,
7871                          sizeof(struct tng_chain) *
7872                          (molecule->n_chains + 1));
7873
7874     if(!new_chains)
7875     {
7876         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7877                sizeof(struct tng_chain) * (molecule->n_chains + 1),
7878                __FILE__, __LINE__);
7879         free(molecule->chains);
7880         molecule->chains = 0;
7881         return(TNG_CRITICAL);
7882     }
7883
7884     molecule->chains = new_chains;
7885
7886     *chain = &new_chains[molecule->n_chains];
7887     (*chain)->name = 0;
7888
7889     tng_chain_name_set(tng_data, *chain, name);
7890
7891     (*chain)->molecule = molecule;
7892     (*chain)->n_residues = 0;
7893
7894     for(i = molecule->n_chains; i--;)
7895     {
7896         if(molecule->chains[i].id == id)
7897         {
7898             stat = TNG_FAILURE;
7899             fprintf(stderr, "TNG library: Chain ID already in use. %s: %d\n", __FILE__, __LINE__);
7900             break;
7901         }
7902     }
7903
7904     molecule->n_chains++;
7905
7906     (*chain)->id = id;
7907
7908     return(stat);
7909 }
7910
7911 tng_function_status DECLSPECDLLEXPORT tng_molecule_bond_add
7912                 (const tng_trajectory_t tng_data,
7913                  tng_molecule_t molecule,
7914                  const int64_t from_atom_id,
7915                  const int64_t to_atom_id,
7916                  tng_bond_t *bond)
7917 {
7918     int64_t i;
7919     tng_bond_t new_bonds;
7920     (void)tng_data;
7921
7922     for(i = 0; i < molecule->n_bonds; i++)
7923     {
7924         *bond = &molecule->bonds[i];
7925         /* Check if the bond already exists */
7926         if(((*bond)->from_atom_id == from_atom_id && (*bond)->to_atom_id == to_atom_id) ||
7927            ((*bond)->to_atom_id == from_atom_id && (*bond)->from_atom_id == to_atom_id))
7928         {
7929             return(TNG_SUCCESS);
7930         }
7931     }
7932
7933     new_bonds = realloc(molecule->bonds,
7934                         sizeof(struct tng_bond) *
7935                         (molecule->n_bonds + 1));
7936
7937     if(!new_bonds)
7938     {
7939         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7940                sizeof(struct tng_bond) * (molecule->n_bonds + 1),
7941                __FILE__, __LINE__);
7942         *bond = 0;
7943         free(molecule->bonds);
7944         molecule->bonds = 0;
7945         return(TNG_CRITICAL);
7946     }
7947
7948     molecule->bonds = new_bonds;
7949
7950     *bond = &new_bonds[molecule->n_bonds];
7951
7952     (*bond)->from_atom_id = from_atom_id;
7953     (*bond)->to_atom_id = to_atom_id;
7954
7955     molecule->n_bonds++;
7956
7957     return(TNG_SUCCESS);
7958 }
7959
7960 tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_find
7961                 (tng_trajectory_t tng_data,
7962                  tng_molecule_t molecule,
7963                  const char *name,
7964                  int64_t id,
7965                  tng_atom_t *atom)
7966 {
7967     int64_t i, n_atoms;
7968     (void)tng_data;
7969
7970     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7971
7972     n_atoms = molecule->n_atoms;
7973
7974     for(i = 0; i < n_atoms; i++)
7975     {
7976         *atom = &molecule->atoms[i];
7977         if(name[0] == 0 || strcmp(name, (*atom)->name) == 0)
7978         {
7979             if(id == -1 || id == (*atom)->id)
7980             {
7981                 return(TNG_SUCCESS);
7982             }
7983         }
7984     }
7985
7986     *atom = 0;
7987
7988     return(TNG_FAILURE);
7989 }
7990
7991 tng_function_status tng_chain_name_get(const tng_trajectory_t tng_data,
7992                                        const tng_chain_t chain,
7993                                        char *name,
7994                                        const int max_len)
7995 {
7996     (void) tng_data;
7997     TNG_ASSERT(chain, "TNG library: chain must not be NULL");
7998     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
7999
8000     strncpy(name, chain->name, max_len - 1);
8001     name[max_len - 1] = 0;
8002
8003     if(strlen(chain->name) > (unsigned int)max_len - 1)
8004     {
8005         return(TNG_FAILURE);
8006     }
8007     return(TNG_SUCCESS);
8008 }
8009
8010 tng_function_status DECLSPECDLLEXPORT tng_chain_name_set
8011                 (tng_trajectory_t tng_data,
8012                  tng_chain_t chain,
8013                  const char *new_name)
8014 {
8015     unsigned int len;
8016     (void)tng_data;
8017
8018     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
8019
8020     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
8021
8022     /* If the currently stored string length is not enough to store the new
8023      * string it is freed and reallocated. */
8024     if(chain->name && strlen(chain->name) < len)
8025     {
8026         free(chain->name);
8027         chain->name = 0;
8028     }
8029     if(!chain->name)
8030     {
8031         chain->name = malloc(len);
8032         if(!chain->name)
8033         {
8034             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
8035                    __FILE__, __LINE__);
8036             return(TNG_CRITICAL);
8037         }
8038     }
8039
8040     strncpy(chain->name, new_name, len);
8041
8042     return(TNG_SUCCESS);
8043 }
8044
8045 tng_function_status DECLSPECDLLEXPORT tng_chain_num_residues_get
8046                 (const tng_trajectory_t tng_data,
8047                  const tng_chain_t chain,
8048                  int64_t *n)
8049 {
8050     (void) tng_data;
8051     TNG_ASSERT(chain, "TNG library: chain must not be NULL");
8052     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8053
8054     *n = chain->n_residues;
8055
8056     return(TNG_SUCCESS);
8057 }
8058
8059 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_of_index_get
8060                 (const tng_trajectory_t tng_data,
8061                  const tng_chain_t chain,
8062                  const int64_t index,
8063                  tng_residue_t *residue)
8064 {
8065     (void) tng_data;
8066     TNG_ASSERT(chain, "TNG library: chain must not be a NULL pointer.");
8067     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
8068
8069     if(index >= chain->n_residues)
8070     {
8071         *residue = 0;
8072         return(TNG_FAILURE);
8073     }
8074     *residue = &chain->residues[index];
8075     return(TNG_SUCCESS);
8076 }
8077
8078 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_find
8079                 (tng_trajectory_t tng_data,
8080                  tng_chain_t chain,
8081                  const char *name,
8082                  int64_t id,
8083                  tng_residue_t *residue)
8084 {
8085     int64_t i, n_residues;
8086     (void)tng_data;
8087
8088     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8089
8090     n_residues = chain->n_residues;
8091
8092     for(i = 0; i < n_residues; i++)
8093     {
8094         *residue = &chain->residues[i];
8095         if(name[0] == 0 || strcmp(name, (*residue)->name) == 0)
8096         {
8097             if(id == -1 || id == (*residue)->id)
8098             {
8099                 return(TNG_SUCCESS);
8100             }
8101         }
8102     }
8103
8104     *residue = 0;
8105
8106     return(TNG_FAILURE);
8107 }
8108
8109 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_add
8110                 (tng_trajectory_t tng_data,
8111                  tng_chain_t chain,
8112                  const char *name,
8113                  tng_residue_t *residue)
8114 {
8115     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8116     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8117
8118     return(tng_chain_residue_w_id_add(tng_data, chain, name,
8119                                       chain->n_residues + 1, residue));
8120 }
8121
8122 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_w_id_add
8123                 (tng_trajectory_t tng_data,
8124                  tng_chain_t chain,
8125                  const char *name,
8126                  const int64_t id,
8127                  tng_residue_t *residue)
8128 {
8129     int64_t i, curr_index;
8130     tng_residue_t new_residues, temp_residue, last_residue;
8131     tng_molecule_t molecule = chain->molecule;
8132     tng_function_status stat = TNG_SUCCESS;
8133
8134     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8135     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8136
8137     if(chain->n_residues)
8138     {
8139         curr_index = chain->residues - molecule->residues;
8140     }
8141     else
8142     {
8143         curr_index = -1;
8144     }
8145
8146     new_residues = realloc(molecule->residues,
8147                            sizeof(struct tng_residue) *
8148                            (molecule->n_residues + 1));
8149
8150     if(!new_residues)
8151     {
8152         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8153                sizeof(struct tng_residue) * (molecule->n_residues + 1),
8154                __FILE__, __LINE__);
8155         free(molecule->residues);
8156         molecule->residues = 0;
8157         return(TNG_CRITICAL);
8158     }
8159
8160     molecule->residues = new_residues;
8161
8162     if(curr_index != -1)
8163     {
8164         chain->residues = new_residues + curr_index;
8165         if(molecule->n_residues)
8166         {
8167             last_residue = &new_residues[molecule->n_residues - 1];
8168
8169             temp_residue = chain->residues + (chain->n_residues - 1);
8170             /* Make space in list of residues to add the new residues together with the other
8171             * residues of this chain */
8172             if(temp_residue != last_residue)
8173             {
8174                 ++temp_residue;
8175                 memmove(temp_residue + 1, temp_residue,
8176                         last_residue - temp_residue);
8177             }
8178         }
8179     }
8180     else
8181     {
8182         curr_index = molecule->n_residues;
8183     }
8184
8185     *residue = &molecule->residues[curr_index + chain->n_residues];
8186
8187     if(!chain->n_residues)
8188     {
8189         chain->residues = *residue;
8190     }
8191
8192     (*residue)->name = 0;
8193     tng_residue_name_set(tng_data, *residue, name);
8194
8195     (*residue)->chain = chain;
8196     (*residue)->n_atoms = 0;
8197     (*residue)->atoms_offset = 0;
8198
8199     for(i = chain->n_residues; i--;)
8200     {
8201         if(chain->residues[i].id == id)
8202         {
8203             stat = TNG_FAILURE;
8204             fprintf(stderr, "TNG library: Residue ID already in use. %s: %d\n", __FILE__, __LINE__);
8205             break;
8206         }
8207     }
8208
8209     chain->n_residues++;
8210     molecule->n_residues++;
8211
8212     (*residue)->id = id;
8213
8214     return(stat);
8215 }
8216
8217 tng_function_status tng_residue_name_get(const tng_trajectory_t tng_data,
8218                                          const tng_residue_t residue,
8219                                          char *name,
8220                                          const int max_len)
8221 {
8222     (void) tng_data;
8223     TNG_ASSERT(residue, "TNG library: residue must not be NULL");
8224     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
8225
8226     strncpy(name, residue->name, max_len - 1);
8227     name[max_len - 1] = 0;
8228
8229     if(strlen(residue->name) > (unsigned int)max_len - 1)
8230     {
8231         return(TNG_FAILURE);
8232     }
8233     return(TNG_SUCCESS);
8234 }
8235
8236 tng_function_status DECLSPECDLLEXPORT tng_residue_name_set(tng_trajectory_t tng_data,
8237                                                            tng_residue_t residue,
8238                                                            const char *new_name)
8239 {
8240     unsigned int len;
8241     (void)tng_data;
8242
8243     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8244     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
8245
8246     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
8247
8248     /* If the currently stored string length is not enough to store the new
8249      * string it is freed and reallocated. */
8250     if(residue->name && strlen(residue->name) < len)
8251     {
8252         free(residue->name);
8253         residue->name = 0;
8254     }
8255     if(!residue->name)
8256     {
8257         residue->name = malloc(len);
8258         if(!residue->name)
8259         {
8260             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
8261                    __FILE__, __LINE__);
8262             return(TNG_CRITICAL);
8263         }
8264     }
8265
8266     strncpy(residue->name, new_name, len);
8267
8268     return(TNG_SUCCESS);
8269 }
8270
8271 tng_function_status DECLSPECDLLEXPORT tng_residue_num_atoms_get
8272                 (const tng_trajectory_t tng_data,
8273                  const tng_residue_t residue,
8274                  int64_t *n)
8275 {
8276     (void) tng_data;
8277     TNG_ASSERT(residue, "TNG library: residue must not be NULL");
8278     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8279
8280     *n = residue->n_atoms;
8281
8282     return(TNG_SUCCESS);
8283 }
8284
8285 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_of_index_get
8286                 (const tng_trajectory_t tng_data,
8287                  const tng_residue_t residue,
8288                  const int64_t index,
8289                  tng_atom_t *atom)
8290 {
8291     tng_chain_t chain;
8292     tng_molecule_t molecule;
8293
8294     (void) tng_data;
8295     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
8296     TNG_ASSERT(atom, "TNG library: atom must not be a NULL pointer.");
8297
8298     if(index >= residue->n_atoms)
8299     {
8300         *atom = 0;
8301         return(TNG_FAILURE);
8302     }
8303     chain = residue->chain;
8304     molecule = chain->molecule;
8305
8306     if(index + residue->atoms_offset >= molecule->n_atoms)
8307     {
8308         *atom = 0;
8309         return(TNG_FAILURE);
8310     }
8311
8312     *atom = &molecule->atoms[residue->atoms_offset + index];
8313     return(TNG_SUCCESS);
8314 }
8315
8316 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_add
8317                 (tng_trajectory_t tng_data,
8318                  tng_residue_t residue,
8319                  const char *atom_name,
8320                  const char *atom_type,
8321                  tng_atom_t *atom)
8322 {
8323     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8324     TNG_ASSERT(atom_name, "TNG library: atom_name must not be a NULL pointer.");
8325     TNG_ASSERT(atom_type, "TNG library: atom_type must not be a NULL pointer.");
8326
8327     return(tng_residue_atom_w_id_add(tng_data, residue, atom_name, atom_type,
8328                                      residue->chain->molecule->n_atoms + 1,
8329                                      atom));
8330 }
8331
8332 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_w_id_add
8333                 (tng_trajectory_t tng_data,
8334                  tng_residue_t residue,
8335                  const char *atom_name,
8336                  const char *atom_type,
8337                  const int64_t id,
8338                  tng_atom_t *atom)
8339 {
8340     int64_t i;
8341     tng_atom_t new_atoms;
8342     tng_molecule_t molecule = residue->chain->molecule;
8343     tng_function_status stat = TNG_SUCCESS;
8344
8345     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8346     TNG_ASSERT(atom_name, "TNG library: atom_name must not be a NULL pointer.");
8347     TNG_ASSERT(atom_type, "TNG library: atom_type must not be a NULL pointer.");
8348
8349     if(!residue->n_atoms)
8350     {
8351         residue->atoms_offset = molecule->n_atoms;
8352     }
8353
8354     new_atoms = realloc(molecule->atoms,
8355                         sizeof(struct tng_atom) *
8356                         (molecule->n_atoms + 1));
8357
8358     if(!new_atoms)
8359     {
8360         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8361                sizeof(struct tng_atom) * (molecule->n_atoms + 1),
8362                __FILE__, __LINE__);
8363         free(molecule->atoms);
8364         molecule->atoms = 0;
8365         return(TNG_CRITICAL);
8366     }
8367
8368     molecule->atoms = new_atoms;
8369
8370     *atom = &new_atoms[molecule->n_atoms];
8371
8372     tng_atom_init(*atom);
8373     tng_atom_name_set(tng_data, *atom, atom_name);
8374     tng_atom_type_set(tng_data, *atom, atom_type);
8375
8376     (*atom)->residue = residue;
8377
8378     for(i = molecule->n_atoms; i--;)
8379     {
8380         if(molecule->atoms[i].id == id)
8381         {
8382             stat = TNG_FAILURE;
8383             fprintf(stderr, "TNG library: Atom ID %"PRId64" already in use. %s: %d\n", id, __FILE__, __LINE__);
8384             break;
8385         }
8386     }
8387
8388     residue->n_atoms++;
8389     molecule->n_atoms++;
8390
8391     (*atom)->id = id;
8392
8393     return(stat);
8394 }
8395
8396 tng_function_status DECLSPECDLLEXPORT tng_molecule_alloc(const tng_trajectory_t tng_data,
8397                                                          tng_molecule_t *molecule_p)
8398 {
8399     *molecule_p = malloc(sizeof(struct tng_molecule));
8400     if(!*molecule_p)
8401     {
8402         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
8403                sizeof(struct tng_molecule), __FILE__, __LINE__);
8404         return(TNG_CRITICAL);
8405     }
8406
8407     tng_molecule_init(tng_data, *molecule_p);
8408
8409     return(TNG_SUCCESS);
8410 }
8411
8412 tng_function_status DECLSPECDLLEXPORT tng_molecule_free(const tng_trajectory_t tng_data,
8413                                                         tng_molecule_t *molecule_p)
8414 {
8415     if(!*molecule_p)
8416     {
8417         return(TNG_SUCCESS);
8418     }
8419
8420     tng_molecule_destroy(tng_data, *molecule_p);
8421
8422     free(*molecule_p);
8423     *molecule_p = 0;
8424
8425     return(TNG_SUCCESS);
8426 }
8427
8428 tng_function_status DECLSPECDLLEXPORT tng_molecule_init(const tng_trajectory_t tng_data,
8429                                                         tng_molecule_t molecule)
8430 {
8431     (void)tng_data;
8432     molecule->quaternary_str = 1;
8433     molecule->name = 0;
8434     molecule->n_chains = 0;
8435     molecule->chains = 0;
8436     molecule->n_residues = 0;
8437     molecule->residues = 0;
8438     molecule->n_atoms = 0;
8439     molecule->atoms = 0;
8440     molecule->n_bonds = 0;
8441     molecule->bonds = 0;
8442
8443     return(TNG_SUCCESS);
8444 }
8445
8446 tng_function_status DECLSPECDLLEXPORT tng_molecule_destroy(const tng_trajectory_t tng_data,
8447                                                            tng_molecule_t molecule)
8448 {
8449     int64_t i;
8450     (void)tng_data;
8451
8452     if(molecule->name)
8453     {
8454         free(molecule->name);
8455         molecule->name = 0;
8456     }
8457
8458     if(molecule->chains)
8459     {
8460         for(i = molecule->n_chains; i--;)
8461         {
8462             if(molecule->chains[i].name)
8463             {
8464                 free(molecule->chains[i].name);
8465                 molecule->chains[i].name = 0;
8466             }
8467         }
8468         free(molecule->chains);
8469         molecule->chains = 0;
8470     }
8471     molecule->n_chains = 0;
8472
8473     if(molecule->residues)
8474     {
8475         for(i = molecule->n_residues; i--;)
8476         {
8477             if(molecule->residues[i].name)
8478             {
8479                 free(molecule->residues[i].name);
8480                 molecule->residues[i].name = 0;
8481             }
8482         }
8483         free(molecule->residues);
8484         molecule->residues = 0;
8485     }
8486     molecule->n_residues = 0;
8487
8488     if(molecule->atoms)
8489     {
8490         for(i = molecule->n_atoms; i--;)
8491         {
8492             tng_atom_destroy(&molecule->atoms[i]);
8493         }
8494         free(molecule->atoms);
8495         molecule->atoms = 0;
8496     }
8497     molecule->n_atoms = 0;
8498
8499     if(molecule->bonds)
8500     {
8501         free(molecule->bonds);
8502         molecule->bonds = 0;
8503     }
8504     molecule->n_bonds = 0;
8505
8506     return(TNG_SUCCESS);
8507 }
8508
8509 tng_function_status DECLSPECDLLEXPORT tng_molecule_name_of_particle_nr_get
8510                 (const tng_trajectory_t tng_data,
8511                  const int64_t nr,
8512                  char *name,
8513                  int max_len)
8514 {
8515     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8516     tng_molecule_t mol;
8517     tng_bool found = TNG_FALSE;
8518
8519     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8520     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8521
8522     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8523
8524     if(!molecule_cnt_list)
8525     {
8526         return(TNG_FAILURE);
8527     }
8528
8529     for(i = 0; i < tng_data->n_molecules; i++)
8530     {
8531         mol = &tng_data->molecules[i];
8532         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8533         {
8534             cnt += mol->n_atoms * molecule_cnt_list[i];
8535             continue;
8536         }
8537         found = TNG_TRUE;
8538         break;
8539     }
8540     if(!found)
8541     {
8542         return(TNG_FAILURE);
8543     }
8544
8545     strncpy(name, mol->name, max_len - 1);
8546     name[max_len - 1] = 0;
8547
8548     if(strlen(mol->name) > (unsigned int)max_len - 1)
8549     {
8550         return(TNG_FAILURE);
8551     }
8552     return(TNG_SUCCESS);
8553 }
8554
8555 tng_function_status DECLSPECDLLEXPORT tng_molecule_id_of_particle_nr_get
8556                 (const tng_trajectory_t tng_data,
8557                  const int64_t nr,
8558                  int64_t *id)
8559 {
8560     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8561     tng_molecule_t mol;
8562     tng_bool found = TNG_FALSE;
8563
8564     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8565     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
8566
8567     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8568
8569     if(!molecule_cnt_list)
8570     {
8571         return(TNG_FAILURE);
8572     }
8573
8574     for(i = 0; i < tng_data->n_molecules; i++)
8575     {
8576         mol = &tng_data->molecules[i];
8577         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8578         {
8579             cnt += mol->n_atoms * molecule_cnt_list[i];
8580             continue;
8581         }
8582         found = TNG_TRUE;
8583         break;
8584     }
8585     if(!found)
8586     {
8587         return(TNG_FAILURE);
8588     }
8589
8590     *id = mol->id;
8591
8592     return(TNG_SUCCESS);
8593 }
8594
8595 tng_function_status DECLSPECDLLEXPORT tng_molsystem_bonds_get
8596                 (const tng_trajectory_t tng_data,
8597                  int64_t *n_bonds,
8598                  int64_t **from_atoms,
8599                  int64_t **to_atoms)
8600 {
8601     int64_t atom_cnt = 0, cnt, mol_cnt, i, j, k;
8602     int64_t from_atom, to_atom, *molecule_cnt_list = 0;
8603     tng_molecule_t mol;
8604     tng_bond_t bond;
8605
8606     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8607     TNG_ASSERT(n_bonds, "TNG library: n_bonds must not be a NULL pointer.");
8608     TNG_ASSERT(from_atoms, "TNG library: from_atoms must not be a NULL pointer.");
8609     TNG_ASSERT(to_atoms, "TNG library: to_atoms must not be a NULL pointer.");
8610
8611     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8612
8613     if(!molecule_cnt_list)
8614     {
8615         return(TNG_FAILURE);
8616     }
8617
8618     *n_bonds = 0;
8619     /* First count the total number of bonds to allocate memory */
8620     for(i = 0; i < tng_data->n_molecules; i++)
8621     {
8622         mol = &tng_data->molecules[i];
8623         mol_cnt = molecule_cnt_list[i];
8624         *n_bonds += mol_cnt * mol->n_bonds;
8625     }
8626     if(*n_bonds == 0)
8627     {
8628         return(TNG_SUCCESS);
8629     }
8630
8631     *from_atoms = malloc(sizeof(int64_t) * (*n_bonds));
8632     if(!*from_atoms)
8633     {
8634         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8635                sizeof(int64_t) * (*n_bonds), __FILE__, __LINE__);
8636         return(TNG_CRITICAL);
8637     }
8638     *to_atoms = malloc(sizeof(int64_t) * (*n_bonds));
8639     if(!*to_atoms)
8640     {
8641         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8642                sizeof(int64_t) * (*n_bonds), __FILE__, __LINE__);
8643         free(*from_atoms);
8644         *from_atoms = 0;
8645         return(TNG_CRITICAL);
8646     }
8647
8648     cnt = 0;
8649     for(i = 0; i < tng_data->n_molecules; i++)
8650     {
8651         mol = &tng_data->molecules[i];
8652         mol_cnt = molecule_cnt_list[i];
8653         for(j = 0; j < mol_cnt; j++)
8654         {
8655             for(k = 0; k < mol->n_bonds; k++)
8656             {
8657                 bond = &mol->bonds[k];
8658                 from_atom = atom_cnt + bond->from_atom_id;
8659                 to_atom = atom_cnt + bond->to_atom_id;
8660                 (*from_atoms)[cnt] = from_atom;
8661                 (*to_atoms)[cnt++] = to_atom;
8662             }
8663             atom_cnt += mol->n_atoms;
8664         }
8665     }
8666
8667     return(TNG_SUCCESS);
8668 }
8669
8670 tng_function_status DECLSPECDLLEXPORT tng_chain_name_of_particle_nr_get
8671                 (const tng_trajectory_t tng_data,
8672                  const int64_t nr,
8673                  char *name,
8674                  int max_len)
8675 {
8676     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8677     tng_molecule_t mol;
8678     tng_atom_t atom;
8679     tng_bool found = TNG_FALSE;
8680
8681     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8682     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8683
8684     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8685
8686     if(!molecule_cnt_list)
8687     {
8688         return(TNG_FAILURE);
8689     }
8690
8691     for(i = 0; i < tng_data->n_molecules; i++)
8692     {
8693         mol = &tng_data->molecules[i];
8694         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8695         {
8696             cnt += mol->n_atoms * molecule_cnt_list[i];
8697             continue;
8698         }
8699         atom = &mol->atoms[nr % mol->n_atoms];
8700         found = TNG_TRUE;
8701         break;
8702     }
8703     if(!found)
8704     {
8705         return(TNG_FAILURE);
8706     }
8707     if(!atom->residue || !atom->residue->chain)
8708     {
8709         return(TNG_FAILURE);
8710     }
8711
8712     strncpy(name, atom->residue->chain->name, max_len - 1);
8713     name[max_len - 1] = 0;
8714
8715     if(strlen(atom->residue->chain->name) > (unsigned int)max_len - 1)
8716     {
8717         return(TNG_FAILURE);
8718     }
8719     return(TNG_SUCCESS);
8720 }
8721
8722 tng_function_status DECLSPECDLLEXPORT tng_residue_name_of_particle_nr_get
8723                 (const tng_trajectory_t tng_data,
8724                  const int64_t nr,
8725                  char *name,
8726                  int max_len)
8727 {
8728     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8729     tng_molecule_t mol;
8730     tng_atom_t atom;
8731     tng_bool found = TNG_FALSE;
8732
8733     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8734     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8735
8736     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8737
8738     if(!molecule_cnt_list)
8739     {
8740         return(TNG_FAILURE);
8741     }
8742
8743     for(i = 0; i < tng_data->n_molecules; i++)
8744     {
8745         mol = &tng_data->molecules[i];
8746         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8747         {
8748             cnt += mol->n_atoms * molecule_cnt_list[i];
8749             continue;
8750         }
8751         atom = &mol->atoms[nr % mol->n_atoms];
8752         found = TNG_TRUE;
8753         break;
8754     }
8755     if(!found)
8756     {
8757         return(TNG_FAILURE);
8758     }
8759     if(!atom->residue)
8760     {
8761         return(TNG_FAILURE);
8762     }
8763
8764     strncpy(name, atom->residue->name, max_len - 1);
8765     name[max_len - 1] = 0;
8766
8767     if(strlen(atom->residue->name) > (unsigned int)max_len - 1)
8768     {
8769         return(TNG_FAILURE);
8770     }
8771     return(TNG_SUCCESS);
8772 }
8773
8774 tng_function_status DECLSPECDLLEXPORT tng_residue_id_of_particle_nr_get
8775                 (const tng_trajectory_t tng_data,
8776                  const int64_t nr,
8777                  int64_t *id)
8778 {
8779     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8780     tng_molecule_t mol;
8781     tng_atom_t atom;
8782     tng_bool found = TNG_FALSE;
8783
8784     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8785     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
8786
8787     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8788
8789     if(!molecule_cnt_list)
8790     {
8791         return(TNG_FAILURE);
8792     }
8793
8794     for(i = 0; i < tng_data->n_molecules; i++)
8795     {
8796         mol = &tng_data->molecules[i];
8797         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8798         {
8799             cnt += mol->n_atoms * molecule_cnt_list[i];
8800             continue;
8801         }
8802         atom = &mol->atoms[nr % mol->n_atoms];
8803         found = TNG_TRUE;
8804         break;
8805     }
8806     if(!found)
8807     {
8808         return(TNG_FAILURE);
8809     }
8810     if(!atom->residue)
8811     {
8812         return(TNG_FAILURE);
8813     }
8814
8815     *id = atom->residue->id;
8816
8817     return(TNG_SUCCESS);
8818 }
8819
8820 tng_function_status DECLSPECDLLEXPORT tng_global_residue_id_of_particle_nr_get
8821                 (const tng_trajectory_t tng_data,
8822                  const int64_t nr,
8823                  int64_t *id)
8824 {
8825     int64_t cnt = 0, i, offset = 0, *molecule_cnt_list = 0;
8826     tng_molecule_t mol;
8827     tng_atom_t atom;
8828     tng_bool found = TNG_FALSE;
8829
8830     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8831     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
8832
8833     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8834
8835     if(!molecule_cnt_list)
8836     {
8837         return(TNG_FAILURE);
8838     }
8839
8840     for(i = 0; i < tng_data->n_molecules; i++)
8841     {
8842         mol = &tng_data->molecules[i];
8843         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8844         {
8845             cnt += mol->n_atoms * molecule_cnt_list[i];
8846             offset += mol->n_residues * molecule_cnt_list[i];
8847             continue;
8848         }
8849         atom = &mol->atoms[nr % mol->n_atoms];
8850         found = TNG_TRUE;
8851         break;
8852     }
8853     if(!found)
8854     {
8855         return(TNG_FAILURE);
8856     }
8857     if(!atom->residue)
8858     {
8859         return(TNG_FAILURE);
8860     }
8861
8862     offset += mol->n_residues * ((nr - cnt) / mol->n_atoms);
8863
8864     *id = atom->residue->id + offset;
8865
8866     return(TNG_SUCCESS);
8867 }
8868
8869 tng_function_status DECLSPECDLLEXPORT tng_atom_name_of_particle_nr_get
8870                 (const tng_trajectory_t tng_data,
8871                  const int64_t nr,
8872                  char *name,
8873                  int max_len)
8874 {
8875     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8876     tng_molecule_t mol;
8877     tng_atom_t atom;
8878     tng_bool found = TNG_FALSE;
8879
8880     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8881     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8882
8883     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8884
8885     if(!molecule_cnt_list)
8886     {
8887         return(TNG_FAILURE);
8888     }
8889
8890     for(i = 0; i < tng_data->n_molecules; i++)
8891     {
8892         mol = &tng_data->molecules[i];
8893         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8894         {
8895             cnt += mol->n_atoms * molecule_cnt_list[i];
8896             continue;
8897         }
8898         atom = &mol->atoms[nr % mol->n_atoms];
8899         found = TNG_TRUE;
8900         break;
8901     }
8902     if(!found)
8903     {
8904         return(TNG_FAILURE);
8905     }
8906
8907     strncpy(name, atom->name, max_len - 1);
8908     name[max_len - 1] = 0;
8909
8910     if(strlen(atom->name) > (unsigned int)max_len - 1)
8911     {
8912         return(TNG_FAILURE);
8913     }
8914     return(TNG_SUCCESS);
8915 }
8916
8917 tng_function_status tng_atom_type_of_particle_nr_get
8918                 (const tng_trajectory_t tng_data,
8919                  const int64_t nr,
8920                  char *type,
8921                  int max_len)
8922 {
8923     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8924     tng_molecule_t mol;
8925     tng_atom_t atom;
8926     tng_bool found = TNG_FALSE;
8927
8928     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8929     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
8930
8931     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8932
8933     if(!molecule_cnt_list)
8934     {
8935         return(TNG_FAILURE);
8936     }
8937
8938     for(i = 0; i < tng_data->n_molecules; i++)
8939     {
8940         mol = &tng_data->molecules[i];
8941         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8942         {
8943             cnt += mol->n_atoms * molecule_cnt_list[i];
8944             continue;
8945         }
8946         atom = &mol->atoms[nr % mol->n_atoms];
8947         found = TNG_TRUE;
8948         break;
8949     }
8950     if(!found)
8951     {
8952         return(TNG_FAILURE);
8953     }
8954
8955     strncpy(type, atom->atom_type, max_len - 1);
8956     type[max_len - 1] = 0;
8957
8958     if(strlen(atom->atom_type) > (unsigned int)max_len - 1)
8959     {
8960         return(TNG_FAILURE);
8961     }
8962     return(TNG_SUCCESS);
8963 }
8964
8965 tng_function_status DECLSPECDLLEXPORT tng_particle_mapping_add
8966                 (tng_trajectory_t tng_data,
8967                  const int64_t num_first_particle,
8968                  const int64_t n_particles,
8969                  const int64_t *mapping_table)
8970 {
8971     int64_t i;
8972     tng_particle_mapping_t mapping;
8973     tng_trajectory_frame_set_t frame_set;
8974
8975     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8976
8977     frame_set = &tng_data->current_trajectory_frame_set;
8978
8979     /* Sanity check of the particle ranges. Split into multiple if
8980      * statements for improved readability */
8981     for(i = 0; i < frame_set->n_mapping_blocks; i++)
8982     {
8983         mapping = &frame_set->mappings[i];
8984         if(num_first_particle >= mapping->num_first_particle &&
8985            num_first_particle < mapping->num_first_particle +
8986                                    mapping->n_particles)
8987         {
8988             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
8989             return(TNG_FAILURE);
8990         }
8991         if(num_first_particle + n_particles >=
8992            mapping->num_first_particle &&
8993            num_first_particle + n_particles <
8994            mapping->num_first_particle + mapping->n_particles)
8995         {
8996             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
8997             return(TNG_FAILURE);
8998         }
8999         if(mapping->num_first_particle >= num_first_particle &&
9000            mapping->num_first_particle < num_first_particle +
9001                                             n_particles)
9002         {
9003             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
9004             return(TNG_FAILURE);
9005         }
9006         if(mapping->num_first_particle + mapping->n_particles >
9007            num_first_particle &&
9008            mapping->num_first_particle + mapping->n_particles <
9009            num_first_particle + n_particles)
9010         {
9011             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
9012             return(TNG_FAILURE);
9013         }
9014     }
9015
9016     frame_set->n_mapping_blocks++;
9017
9018     mapping = realloc(frame_set->mappings, sizeof(struct tng_particle_mapping) *
9019                       frame_set->n_mapping_blocks);
9020
9021     if(!mapping)
9022     {
9023         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9024                sizeof(struct tng_particle_mapping)*frame_set->n_mapping_blocks,
9025                __FILE__, __LINE__);
9026         free(frame_set->mappings);
9027         frame_set->mappings = 0;
9028         return(TNG_CRITICAL);
9029     }
9030     frame_set->mappings = mapping;
9031
9032     frame_set->mappings[frame_set->n_mapping_blocks - 1].num_first_particle = num_first_particle;
9033     frame_set->mappings[frame_set->n_mapping_blocks - 1].n_particles = n_particles;
9034
9035     frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers = malloc(sizeof(int64_t) * n_particles);
9036     if(!frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers)
9037     {
9038         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9039                sizeof(int64_t) * n_particles, __FILE__, __LINE__);
9040         return(TNG_CRITICAL);
9041     }
9042
9043     for(i=0; i<n_particles; i++)
9044     {
9045         frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers[i] = mapping_table[i];
9046     }
9047
9048     return(TNG_SUCCESS);
9049 }
9050
9051 tng_function_status DECLSPECDLLEXPORT tng_frame_set_particle_mapping_free(tng_trajectory_t tng_data)
9052 {
9053     tng_trajectory_frame_set_t frame_set;
9054     tng_particle_mapping_t mapping;
9055     int64_t i;
9056
9057     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9058
9059     frame_set = &tng_data->current_trajectory_frame_set;
9060
9061     if(frame_set->n_mapping_blocks && frame_set->mappings)
9062     {
9063         for(i = frame_set->n_mapping_blocks; i--;)
9064         {
9065             mapping = &frame_set->mappings[i];
9066             if(mapping->real_particle_numbers)
9067             {
9068                 free(mapping->real_particle_numbers);
9069                 mapping->real_particle_numbers = 0;
9070             }
9071         }
9072         free(frame_set->mappings);
9073         frame_set->mappings = 0;
9074         frame_set->n_mapping_blocks = 0;
9075     }
9076
9077     return(TNG_SUCCESS);
9078 }
9079
9080 tng_function_status DECLSPECDLLEXPORT tng_trajectory_init(tng_trajectory_t *tng_data_p)
9081 {
9082     time_t seconds;
9083     tng_trajectory_frame_set_t frame_set;
9084     tng_trajectory_t tng_data;
9085
9086     *tng_data_p = malloc(sizeof(struct tng_trajectory));
9087     if(!*tng_data_p)
9088     {
9089         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
9090                sizeof(struct tng_trajectory), __FILE__, __LINE__);
9091         return(TNG_CRITICAL);
9092     }
9093
9094     tng_data = *tng_data_p;
9095
9096     frame_set = &tng_data->current_trajectory_frame_set;
9097
9098     tng_data->input_file_path = 0;
9099     tng_data->input_file = 0;
9100     tng_data->input_file_len = 0;
9101     tng_data->output_file_path = 0;
9102     tng_data->output_file = 0;
9103
9104     tng_data->first_program_name = 0;
9105     tng_data->first_user_name = 0;
9106     tng_data->first_computer_name = 0;
9107     tng_data->first_pgp_signature = 0;
9108     tng_data->last_program_name = 0;
9109     tng_data->last_user_name = 0;
9110     tng_data->last_computer_name = 0;
9111     tng_data->last_pgp_signature = 0;
9112     tng_data->forcefield_name = 0;
9113
9114     seconds = time(0);
9115     if ( seconds == -1)
9116     {
9117         fprintf(stderr, "TNG library: Cannot get time. %s: %d\n", __FILE__, __LINE__);
9118     }
9119     else
9120     {
9121         tng_data->time = seconds;
9122     }
9123
9124     tng_data->var_num_atoms_flag = TNG_CONSTANT_N_ATOMS;
9125     tng_data->first_trajectory_frame_set_input_file_pos = -1;
9126     tng_data->last_trajectory_frame_set_input_file_pos = -1;
9127     tng_data->current_trajectory_frame_set_input_file_pos = -1;
9128     tng_data->first_trajectory_frame_set_output_file_pos = -1;
9129     tng_data->last_trajectory_frame_set_output_file_pos = -1;
9130     tng_data->current_trajectory_frame_set_output_file_pos = -1;
9131     tng_data->frame_set_n_frames = 100;
9132     tng_data->n_trajectory_frame_sets = 0;
9133     tng_data->n_trajectory_blocks = 0;
9134     tng_data->medium_stride_length = 100;
9135     tng_data->long_stride_length = 10000;
9136
9137     tng_data->time_per_frame = -1;
9138
9139     tng_data->n_particle_data_blocks = 0;
9140     tng_data->n_data_blocks = 0;
9141
9142     tng_data->non_tr_particle_data = 0;
9143     tng_data->non_tr_data = 0;
9144
9145     tng_data->compress_algo_pos = 0;
9146     tng_data->compress_algo_vel = 0;
9147     tng_data->compression_precision = 1000;
9148     tng_data->distance_unit_exponential = -9;
9149
9150     frame_set->first_frame = -1;
9151     frame_set->n_mapping_blocks = 0;
9152     frame_set->mappings = 0;
9153     frame_set->molecule_cnt_list = 0;
9154
9155     frame_set->n_particle_data_blocks = 0;
9156     frame_set->n_data_blocks = 0;
9157
9158     frame_set->tr_particle_data = 0;
9159     frame_set->tr_data = 0;
9160
9161     frame_set->n_written_frames = 0;
9162     frame_set->n_unwritten_frames = 0;
9163
9164     frame_set->next_frame_set_file_pos = -1;
9165     frame_set->prev_frame_set_file_pos = -1;
9166     frame_set->medium_stride_next_frame_set_file_pos = -1;
9167     frame_set->medium_stride_prev_frame_set_file_pos = -1;
9168     frame_set->long_stride_next_frame_set_file_pos = -1;
9169     frame_set->long_stride_prev_frame_set_file_pos = -1;
9170
9171     frame_set->first_frame_time = -1;
9172
9173     tng_data->n_molecules = 0;
9174     tng_data->molecules = 0;
9175     tng_data->molecule_cnt_list = 0;
9176     tng_data->n_particles = 0;
9177
9178     {
9179       /* Check the endianness of the computer */
9180       static int32_t endianness_32 = 0x01234567;
9181       /* 0x01234567 */
9182       if ( *(const unsigned char*)&endianness_32 == 0x01 )
9183         {
9184           tng_data->endianness_32 = TNG_BIG_ENDIAN_32;
9185         }
9186
9187       /* 0x67452301 */
9188       else if( *(const unsigned char*)&endianness_32 == 0x67 )
9189         {
9190           tng_data->endianness_32 = TNG_LITTLE_ENDIAN_32;
9191
9192         }
9193
9194       /* 0x45670123 */
9195       else if ( *(const unsigned char*)&endianness_32 == 0x45 )
9196         {
9197           tng_data->endianness_32 = TNG_BYTE_PAIR_SWAP_32;
9198         }
9199     }
9200     {
9201       static int64_t endianness_64 = 0x0123456789ABCDEFLL;
9202       /* 0x0123456789ABCDEF */
9203       if ( *(const unsigned char*)&endianness_64 == 0x01 )
9204         {
9205           tng_data->endianness_64 = TNG_BIG_ENDIAN_64;
9206         }
9207
9208       /* 0xEFCDAB8967452301 */
9209       else if ( *(const unsigned char*)&endianness_64 == 0xEF )
9210         {
9211           tng_data->endianness_64 = TNG_LITTLE_ENDIAN_64;
9212         }
9213
9214       /* 0x89ABCDEF01234567 */
9215       else if ( *(const unsigned char*)&endianness_64 == 0x89 )
9216         {
9217           tng_data->endianness_64 = TNG_QUAD_SWAP_64;
9218         }
9219
9220       /* 0x45670123CDEF89AB */
9221       else if ( *(const unsigned char*)&endianness_64 == 0x45 )
9222         {
9223           tng_data->endianness_64 = TNG_BYTE_PAIR_SWAP_64;
9224         }
9225
9226       /* 0x23016745AB89EFCD */
9227       else if ( *(const unsigned char*)&endianness_64 == 0x23 )
9228         {
9229           tng_data->endianness_64 = TNG_BYTE_SWAP_64;
9230         }
9231     }
9232
9233     /* By default do not swap the byte order, i.e. keep the byte order of the
9234      * architecture. The input file endianness will be set when reading the
9235      * header. The output endianness can be changed - before the file is
9236      * written. */
9237     tng_data->input_endianness_swap_func_32 = 0;
9238     tng_data->input_endianness_swap_func_64 = 0;
9239     tng_data->output_endianness_swap_func_32 = 0;
9240     tng_data->output_endianness_swap_func_64 = 0;
9241
9242     tng_data->current_trajectory_frame_set.next_frame_set_file_pos = -1;
9243     tng_data->current_trajectory_frame_set.prev_frame_set_file_pos = -1;
9244     tng_data->current_trajectory_frame_set.n_frames = 0;
9245
9246     return(TNG_SUCCESS);
9247 }
9248
9249 tng_function_status DECLSPECDLLEXPORT tng_trajectory_destroy(tng_trajectory_t *tng_data_p)
9250 {
9251     int64_t i, j, k, l;
9252     int64_t n_particles, n_values_per_frame;
9253     tng_trajectory_t tng_data = *tng_data_p;
9254     tng_trajectory_frame_set_t frame_set;
9255
9256     if(!*tng_data_p)
9257     {
9258         return(TNG_SUCCESS);
9259     }
9260
9261     frame_set = &tng_data->current_trajectory_frame_set;
9262
9263     if(tng_data->input_file_path)
9264     {
9265         free(tng_data->input_file_path);
9266         tng_data->input_file_path = 0;
9267     }
9268
9269     if(tng_data->input_file)
9270     {
9271         fclose(tng_data->input_file);
9272         tng_data->input_file = 0;
9273     }
9274
9275     if(tng_data->output_file_path)
9276     {
9277         free(tng_data->output_file_path);
9278         tng_data->output_file_path = 0;
9279     }
9280
9281     if(tng_data->output_file)
9282     {
9283         /* FIXME: Do not always write the hash */
9284         tng_frame_set_finalize(tng_data, TNG_USE_HASH);
9285         fclose(tng_data->output_file);
9286         tng_data->output_file = 0;
9287     }
9288
9289     if(tng_data->first_program_name)
9290     {
9291         free(tng_data->first_program_name);
9292         tng_data->first_program_name = 0;
9293     }
9294
9295     if(tng_data->last_program_name)
9296     {
9297         free(tng_data->last_program_name);
9298         tng_data->last_program_name = 0;
9299     }
9300
9301     if(tng_data->first_user_name)
9302     {
9303         free(tng_data->first_user_name);
9304         tng_data->first_user_name = 0;
9305     }
9306
9307     if(tng_data->last_user_name)
9308     {
9309         free(tng_data->last_user_name);
9310         tng_data->last_user_name = 0;
9311     }
9312
9313     if(tng_data->first_computer_name)
9314     {
9315         free(tng_data->first_computer_name);
9316         tng_data->first_computer_name = 0;
9317     }
9318
9319     if(tng_data->last_computer_name)
9320     {
9321         free(tng_data->last_computer_name);
9322         tng_data->last_computer_name = 0;
9323     }
9324
9325     if(tng_data->first_pgp_signature)
9326     {
9327         free(tng_data->first_pgp_signature);
9328         tng_data->first_pgp_signature = 0;
9329     }
9330
9331     if(tng_data->last_pgp_signature)
9332     {
9333         free(tng_data->last_pgp_signature);
9334         tng_data->last_pgp_signature = 0;
9335     }
9336
9337     if(tng_data->forcefield_name)
9338     {
9339         free(tng_data->forcefield_name);
9340         tng_data->forcefield_name = 0;
9341     }
9342
9343     tng_frame_set_particle_mapping_free(tng_data);
9344
9345     if(frame_set->molecule_cnt_list)
9346     {
9347         free(frame_set->molecule_cnt_list);
9348         frame_set->molecule_cnt_list = 0;
9349     }
9350
9351     if(tng_data->var_num_atoms_flag)
9352     {
9353         n_particles = frame_set->n_particles;
9354     }
9355     else
9356     {
9357         n_particles = tng_data->n_particles;
9358     }
9359
9360     if(tng_data->non_tr_particle_data)
9361     {
9362         for(i = tng_data->n_particle_data_blocks; i--; )
9363         {
9364             if(tng_data->non_tr_particle_data[i].values)
9365             {
9366                 free(tng_data->non_tr_particle_data[i].values);
9367                 tng_data->non_tr_particle_data[i].values = 0;
9368             }
9369
9370             if(tng_data->non_tr_particle_data[i].strings)
9371             {
9372                 n_values_per_frame = tng_data->non_tr_particle_data[i].
9373                                      n_values_per_frame;
9374                 if(tng_data->non_tr_particle_data[i].strings[0])
9375                 {
9376                     for(j = n_particles; j--;)
9377                     {
9378                         if(tng_data->non_tr_particle_data[i].strings[0][j])
9379                         {
9380                             for(k = n_values_per_frame; k--;)
9381                             {
9382                                 if(tng_data->non_tr_particle_data[i].
9383                                    strings[0][j][k])
9384                                 {
9385                                     free(tng_data->non_tr_particle_data[i].
9386                                          strings[0][j][k]);
9387                                     tng_data->non_tr_particle_data[i].
9388                                     strings[0][j][k] = 0;
9389                                 }
9390                             }
9391                             free(tng_data->non_tr_particle_data[i].
9392                                  strings[0][j]);
9393                             tng_data->non_tr_particle_data[i].strings[0][j] = 0;
9394                         }
9395                     }
9396                     free(tng_data->non_tr_particle_data[i].strings[0]);
9397                     tng_data->non_tr_particle_data[i].strings[0] = 0;
9398                 }
9399                 free(tng_data->non_tr_particle_data[i].strings);
9400                 tng_data->non_tr_particle_data[i].strings = 0;
9401             }
9402
9403             if(tng_data->non_tr_particle_data[i].block_name)
9404             {
9405                 free(tng_data->non_tr_particle_data[i].block_name);
9406                 tng_data->non_tr_particle_data[i].block_name = 0;
9407             }
9408         }
9409         free(tng_data->non_tr_particle_data);
9410         tng_data->non_tr_particle_data = 0;
9411     }
9412
9413     if(tng_data->non_tr_data)
9414     {
9415         for(i = tng_data->n_data_blocks; i--;)
9416         {
9417             if(tng_data->non_tr_data[i].values)
9418             {
9419                 free(tng_data->non_tr_data[i].values);
9420                 tng_data->non_tr_data[i].values = 0;
9421             }
9422
9423             if(tng_data->non_tr_data[i].strings)
9424             {
9425                 n_values_per_frame = tng_data->non_tr_data[i].
9426                                      n_values_per_frame;
9427                 if(tng_data->non_tr_data[i].strings[0])
9428                 {
9429                     for(j = n_values_per_frame; j--;)
9430                     {
9431                         if(tng_data->non_tr_data[i].strings[0][j])
9432                         {
9433                             free(tng_data->non_tr_data[i].strings[0][j]);
9434                             tng_data->non_tr_data[i].strings[0][j] = 0;
9435                         }
9436                     }
9437                     free(tng_data->non_tr_data[i].strings[0]);
9438                     tng_data->non_tr_data[i].strings[0] = 0;
9439                 }
9440                 free(tng_data->non_tr_data[i].strings);
9441                 tng_data->non_tr_data[i].strings = 0;
9442             }
9443
9444             if(tng_data->non_tr_data[i].block_name)
9445             {
9446                 free(tng_data->non_tr_data[i].block_name);
9447                 tng_data->non_tr_data[i].block_name = 0;
9448             }
9449         }
9450         free(tng_data->non_tr_data);
9451         tng_data->non_tr_data = 0;
9452     }
9453
9454     tng_data->n_particle_data_blocks = 0;
9455     tng_data->n_data_blocks = 0;
9456
9457     if(tng_data->compress_algo_pos)
9458     {
9459         free(tng_data->compress_algo_pos);
9460         tng_data->compress_algo_pos = 0;
9461     }
9462     if(tng_data->compress_algo_vel)
9463     {
9464         free(tng_data->compress_algo_vel);
9465         tng_data->compress_algo_vel = 0;
9466     }
9467
9468     if(frame_set->tr_particle_data)
9469     {
9470         for(i = frame_set->n_particle_data_blocks; i--; )
9471         {
9472             if(frame_set->tr_particle_data[i].values)
9473             {
9474                 free(frame_set->tr_particle_data[i].values);
9475                 frame_set->tr_particle_data[i].values = 0;
9476             }
9477
9478             if(frame_set->tr_particle_data[i].strings)
9479             {
9480                 n_values_per_frame = frame_set->tr_particle_data[i].
9481                                      n_values_per_frame;
9482                 for(j = frame_set->tr_particle_data[i].n_frames; j--;)
9483                 {
9484                     if(frame_set->tr_particle_data[i].strings[j])
9485                     {
9486                         for(k = n_particles; k--;)
9487                         {
9488                             if(frame_set->tr_particle_data[i].
9489                                 strings[j][k])
9490                             {
9491                                 for(l = n_values_per_frame; l--;)
9492                                 {
9493                                     if(frame_set->tr_particle_data[i].
9494                                         strings[j][k][l])
9495                                     {
9496                                         free(frame_set->tr_particle_data[i].
9497                                                 strings[j][k][l]);
9498                                         frame_set->tr_particle_data[i].
9499                                         strings[j][k][l] = 0;
9500                                     }
9501                                 }
9502                                 free(frame_set->tr_particle_data[i].
9503                                         strings[j][k]);
9504                                 frame_set->tr_particle_data[i].
9505                                 strings[j][k] = 0;
9506                             }
9507                         }
9508                         free(frame_set->tr_particle_data[i].strings[j]);
9509                         frame_set->tr_particle_data[i].strings[j] = 0;
9510                     }
9511                 }
9512                 free(frame_set->tr_particle_data[i].strings);
9513                 frame_set->tr_particle_data[i].strings = 0;
9514             }
9515
9516             if(frame_set->tr_particle_data[i].block_name)
9517             {
9518                 free(frame_set->tr_particle_data[i].block_name);
9519                 frame_set->tr_particle_data[i].block_name = 0;
9520             }
9521         }
9522         free(frame_set->tr_particle_data);
9523         frame_set->tr_particle_data = 0;
9524     }
9525
9526     if(frame_set->tr_data)
9527     {
9528         for(i = frame_set->n_data_blocks; i--;)
9529         {
9530             if(frame_set->tr_data[i].values)
9531             {
9532                 free(frame_set->tr_data[i].values);
9533                 frame_set->tr_data[i].values = 0;
9534             }
9535
9536             if(frame_set->tr_data[i].strings)
9537             {
9538                 n_values_per_frame = frame_set->tr_data[i].
9539                                      n_values_per_frame;
9540                 for(j = frame_set->tr_data[i].n_frames; j--;)
9541                 {
9542                     if(frame_set->tr_data[i].strings[j])
9543                     {
9544                         for(k = n_values_per_frame; k--;)
9545                         {
9546                             if(frame_set->tr_data[i].strings[j][k])
9547                             {
9548                                 free(frame_set->tr_data[i].strings[j][k]);
9549                                 frame_set->tr_data[i].strings[j][k] = 0;
9550                             }
9551                         }
9552                         free(frame_set->tr_data[i].strings[j]);
9553                         frame_set->tr_data[i].strings[j] = 0;
9554                     }
9555                 }
9556                 free(frame_set->tr_data[i].strings);
9557                 frame_set->tr_data[i].strings = 0;
9558             }
9559
9560             if(frame_set->tr_data[i].block_name)
9561             {
9562                 free(frame_set->tr_data[i].block_name);
9563                 frame_set->tr_data[i].block_name = 0;
9564             }
9565         }
9566         free(frame_set->tr_data);
9567         frame_set->tr_data = 0;
9568     }
9569
9570     frame_set->n_particle_data_blocks = 0;
9571     frame_set->n_data_blocks = 0;
9572
9573     if(tng_data->molecules)
9574     {
9575         for(i=tng_data->n_molecules; i--;)
9576         {
9577             tng_molecule_destroy(tng_data, &tng_data->molecules[i]);
9578         }
9579         free(tng_data->molecules);
9580         tng_data->molecules = 0;
9581         tng_data->n_molecules = 0;
9582     }
9583     if(tng_data->molecule_cnt_list)
9584     {
9585         free(tng_data->molecule_cnt_list);
9586         tng_data->molecule_cnt_list = 0;
9587     }
9588
9589     free(*tng_data_p);
9590     *tng_data_p = 0;
9591
9592     return(TNG_SUCCESS);
9593 }
9594
9595 tng_function_status DECLSPECDLLEXPORT tng_trajectory_init_from_src(tng_trajectory_t src,
9596                                                  tng_trajectory_t *dest_p)
9597 {
9598     tng_trajectory_frame_set_t frame_set;
9599     tng_trajectory_t dest;
9600
9601     TNG_ASSERT(src != 0, "TNG library: Source trajectory must not be NULL.");
9602
9603     *dest_p = malloc(sizeof(struct tng_trajectory));
9604     if(!*dest_p)
9605     {
9606         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
9607                sizeof(struct tng_trajectory), __FILE__, __LINE__);
9608         return(TNG_CRITICAL);
9609     }
9610
9611     dest = *dest_p;
9612
9613     frame_set = &dest->current_trajectory_frame_set;
9614
9615     dest->input_file_path = malloc(strlen(src->input_file_path) + 1);
9616     if(!dest->input_file_path)
9617     {
9618         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
9619                (int)strlen(src->input_file_path) + 1, __FILE__, __LINE__);
9620         return(TNG_CRITICAL);
9621     }
9622     strcpy(dest->input_file_path, src->input_file_path);
9623     dest->input_file = 0;
9624     dest->input_file_len = src->input_file_len;
9625     dest->output_file_path = malloc(strlen(src->output_file_path) + 1);
9626     if(!dest->output_file_path)
9627     {
9628         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
9629                (int)strlen(src->output_file_path) + 1, __FILE__, __LINE__);
9630         return(TNG_CRITICAL);
9631     }
9632     strcpy(dest->output_file_path, src->output_file_path);
9633     dest->output_file = 0;
9634
9635     dest->first_program_name = 0;
9636     dest->first_user_name = 0;
9637     dest->first_computer_name = 0;
9638     dest->first_pgp_signature = 0;
9639     dest->last_program_name = 0;
9640     dest->last_user_name = 0;
9641     dest->last_computer_name = 0;
9642     dest->last_pgp_signature = 0;
9643     dest->forcefield_name = 0;
9644
9645     dest->var_num_atoms_flag = src->var_num_atoms_flag;
9646     dest->first_trajectory_frame_set_input_file_pos =
9647     src->first_trajectory_frame_set_input_file_pos;
9648     dest->last_trajectory_frame_set_input_file_pos =
9649     src->last_trajectory_frame_set_input_file_pos;
9650     dest->current_trajectory_frame_set_input_file_pos =
9651     src->current_trajectory_frame_set_input_file_pos;
9652     dest->first_trajectory_frame_set_output_file_pos =
9653     src->first_trajectory_frame_set_output_file_pos;
9654     dest->last_trajectory_frame_set_output_file_pos =
9655     src->last_trajectory_frame_set_output_file_pos;
9656     dest->current_trajectory_frame_set_output_file_pos =
9657     src->current_trajectory_frame_set_output_file_pos;
9658     dest->frame_set_n_frames = src->frame_set_n_frames;
9659     dest->n_trajectory_frame_sets = src->n_trajectory_frame_sets;
9660     dest->n_trajectory_blocks = src->n_trajectory_blocks;
9661     dest->medium_stride_length = src->medium_stride_length;
9662     dest->long_stride_length = src->long_stride_length;
9663
9664     dest->time_per_frame = src->time_per_frame;
9665
9666     /* Currently the non trajectory data blocks are not copied since it
9667      * can lead to problems when freeing memory in a parallel block. */
9668     dest->n_particle_data_blocks = 0;
9669     dest->n_data_blocks = 0;
9670     dest->non_tr_particle_data = 0;
9671     dest->non_tr_data = 0;
9672
9673     dest->compress_algo_pos = 0;
9674     dest->compress_algo_vel = 0;
9675     dest->distance_unit_exponential = -9;
9676     dest->compression_precision = 1000;
9677
9678     frame_set->n_mapping_blocks = 0;
9679     frame_set->mappings = 0;
9680     frame_set->molecule_cnt_list = 0;
9681
9682     frame_set->n_particle_data_blocks = 0;
9683     frame_set->n_data_blocks = 0;
9684
9685     frame_set->tr_particle_data = 0;
9686     frame_set->tr_data = 0;
9687
9688     frame_set->next_frame_set_file_pos = -1;
9689     frame_set->prev_frame_set_file_pos = -1;
9690     frame_set->medium_stride_next_frame_set_file_pos = -1;
9691     frame_set->medium_stride_prev_frame_set_file_pos = -1;
9692     frame_set->long_stride_next_frame_set_file_pos = -1;
9693     frame_set->long_stride_prev_frame_set_file_pos = -1;
9694     frame_set->first_frame = -1;
9695
9696     dest->n_molecules = 0;
9697     dest->molecules = 0;
9698     dest->molecule_cnt_list = 0;
9699     dest->n_particles = src->n_particles;
9700
9701     dest->endianness_32 = src->endianness_32;
9702     dest->endianness_64 = src->endianness_64;
9703     dest->input_endianness_swap_func_32 = src->input_endianness_swap_func_32;
9704     dest->input_endianness_swap_func_64 = src->input_endianness_swap_func_64;
9705     dest->output_endianness_swap_func_32 = src->output_endianness_swap_func_32;
9706     dest->output_endianness_swap_func_64 = src->output_endianness_swap_func_64;
9707
9708     dest->current_trajectory_frame_set.next_frame_set_file_pos = -1;
9709     dest->current_trajectory_frame_set.prev_frame_set_file_pos = -1;
9710     dest->current_trajectory_frame_set.n_frames = 0;
9711
9712     return(TNG_SUCCESS);
9713 }
9714
9715 tng_function_status DECLSPECDLLEXPORT tng_input_file_get(const tng_trajectory_t tng_data,
9716                                        char *file_name, const int max_len)
9717 {
9718     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9719     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9720
9721     strncpy(file_name, tng_data->input_file_path, max_len - 1);
9722     file_name[max_len - 1] = 0;
9723
9724     if(strlen(tng_data->input_file_path) > (unsigned int)max_len - 1)
9725     {
9726         return(TNG_FAILURE);
9727     }
9728     return(TNG_SUCCESS);
9729 }
9730
9731 tng_function_status DECLSPECDLLEXPORT tng_input_file_set(tng_trajectory_t tng_data,
9732                                                          const char *file_name)
9733 {
9734     unsigned int len;
9735     char *temp;
9736
9737     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9738     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9739
9740
9741     if(tng_data->input_file_path && strcmp(tng_data->input_file_path,
9742                                            file_name) == 0)
9743     {
9744         return(TNG_SUCCESS);
9745     }
9746
9747     if(tng_data->input_file)
9748     {
9749         fclose(tng_data->input_file);
9750     }
9751
9752     len = tng_min_i((int)strlen(file_name) + 1, TNG_MAX_STR_LEN);
9753     temp = realloc(tng_data->input_file_path, len);
9754     if(!temp)
9755     {
9756         fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
9757                __FILE__, __LINE__);
9758         free(tng_data->input_file_path);
9759         tng_data->input_file_path = 0;
9760         return(TNG_CRITICAL);
9761     }
9762     tng_data->input_file_path = temp;
9763
9764     strncpy(tng_data->input_file_path, file_name, len);
9765
9766     return(tng_input_file_init(tng_data));
9767 }
9768
9769 tng_function_status tng_output_file_get(const tng_trajectory_t tng_data,
9770                                        char *file_name, const int max_len)
9771 {
9772     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9773     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9774
9775     strncpy(file_name, tng_data->output_file_path, max_len - 1);
9776     file_name[max_len - 1] = 0;
9777
9778     if(strlen(tng_data->output_file_path) > (unsigned int)max_len - 1)
9779     {
9780         return(TNG_FAILURE);
9781     }
9782     return(TNG_SUCCESS);
9783 }
9784
9785 tng_function_status DECLSPECDLLEXPORT tng_output_file_set(tng_trajectory_t tng_data,
9786                                                           const char *file_name)
9787 {
9788     int len;
9789     char *temp;
9790
9791     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9792     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9793
9794     if(tng_data->output_file_path &&
9795        strcmp(tng_data->output_file_path, file_name) == 0)
9796     {
9797         return(TNG_SUCCESS);
9798     }
9799
9800     if(tng_data->output_file)
9801     {
9802         fclose(tng_data->output_file);
9803     }
9804
9805     len = tng_min_i((int)strlen(file_name) + 1, TNG_MAX_STR_LEN);
9806     temp = realloc(tng_data->output_file_path, len);
9807     if(!temp)
9808     {
9809         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
9810                __FILE__, __LINE__);
9811         free(tng_data->output_file_path);
9812         tng_data->output_file_path = 0;
9813         return(TNG_CRITICAL);
9814     }
9815     tng_data->output_file_path = temp;
9816
9817     strncpy(tng_data->output_file_path, file_name, len);
9818
9819     return(tng_output_file_init(tng_data));
9820 }
9821
9822 tng_function_status DECLSPECDLLEXPORT tng_output_append_file_set
9823                 (tng_trajectory_t tng_data,
9824                  const char *file_name)
9825 {
9826     int len;
9827     char *temp;
9828
9829     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9830     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9831
9832     if(tng_data->output_file_path &&
9833        strcmp(tng_data->output_file_path, file_name) == 0)
9834     {
9835         return(TNG_SUCCESS);
9836     }
9837
9838     if(tng_data->output_file)
9839     {
9840         fclose(tng_data->output_file);
9841     }
9842
9843     len = tng_min_i((int)strlen(file_name) + 1, TNG_MAX_STR_LEN);
9844     temp = realloc(tng_data->output_file_path, len);
9845     if(!temp)
9846     {
9847         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
9848                __FILE__, __LINE__);
9849         free(tng_data->output_file_path);
9850         tng_data->output_file_path = 0;
9851         return(TNG_CRITICAL);
9852     }
9853     tng_data->output_file_path = temp;
9854
9855     strncpy(tng_data->output_file_path, file_name, len);
9856
9857     tng_data->output_file = fopen(tng_data->output_file_path, "rb+");
9858     if(!tng_data->output_file)
9859     {
9860         fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
9861                 tng_data->output_file_path, __FILE__, __LINE__);
9862         return(TNG_CRITICAL);
9863     }
9864
9865     return(TNG_SUCCESS);
9866 }
9867
9868 tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_get
9869                 (const tng_trajectory_t tng_data, tng_file_endianness *endianness)
9870 {
9871     tng_endianness_32 end_32;
9872     tng_endianness_64 end_64;
9873
9874     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9875     TNG_ASSERT(endianness, "TNG library: endianness must not be a NULL pointer");
9876
9877     if(tng_data->output_endianness_swap_func_32)
9878     {
9879         /* If other endianness variants are added they must be added here as well */
9880         if(tng_data->output_endianness_swap_func_32 ==
9881            &tng_swap_byte_order_big_endian_32)
9882         {
9883             end_32 = TNG_BIG_ENDIAN_32;
9884         }
9885         else if(tng_data->output_endianness_swap_func_32 ==
9886                 &tng_swap_byte_order_little_endian_32)
9887         {
9888             end_32 = TNG_LITTLE_ENDIAN_32;
9889         }
9890         else
9891         {
9892             return(TNG_FAILURE);
9893         }
9894     }
9895     else
9896     {
9897         end_32 = (tng_endianness_32)tng_data->endianness_32;
9898     }
9899
9900     if(tng_data->output_endianness_swap_func_64)
9901     {
9902         /* If other endianness variants are added they must be added here as well */
9903         if(tng_data->output_endianness_swap_func_64 ==
9904            &tng_swap_byte_order_big_endian_64)
9905         {
9906             end_64 = TNG_BIG_ENDIAN_64;
9907         }
9908         else if(tng_data->output_endianness_swap_func_64 ==
9909                 &tng_swap_byte_order_little_endian_64)
9910         {
9911             end_64 = TNG_LITTLE_ENDIAN_64;
9912         }
9913         else
9914         {
9915             return(TNG_FAILURE);
9916         }
9917     }
9918     else
9919     {
9920         end_64 = (tng_endianness_64)tng_data->endianness_64;
9921     }
9922
9923     if((int)end_32 != (int)end_64)
9924     {
9925         return(TNG_FAILURE);
9926     }
9927
9928     if(end_32 == TNG_LITTLE_ENDIAN_32)
9929     {
9930         *endianness = TNG_LITTLE_ENDIAN;
9931     }
9932
9933     else if(end_32 == TNG_BIG_ENDIAN_32)
9934     {
9935         *endianness = TNG_BIG_ENDIAN;
9936     }
9937     else
9938     {
9939         return(TNG_FAILURE);
9940     }
9941
9942     return(TNG_SUCCESS);
9943 }
9944
9945 tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_set
9946                 (tng_trajectory_t tng_data,
9947                  const tng_file_endianness endianness)
9948 {
9949     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9950
9951     /* Tne endianness cannot be changed if the data has already been written
9952      * to the output file. */
9953     if(ftell(tng_data->output_file) > 0)
9954     {
9955         return(TNG_FAILURE);
9956     }
9957
9958     if(endianness == TNG_BIG_ENDIAN)
9959     {
9960         if(tng_data->endianness_32 == TNG_BIG_ENDIAN_32)
9961         {
9962             tng_data->output_endianness_swap_func_32 = 0;
9963         }
9964         else
9965         {
9966             tng_data->output_endianness_swap_func_32 =
9967             &tng_swap_byte_order_big_endian_32;
9968         }
9969         if(tng_data->endianness_64 == TNG_BIG_ENDIAN_64)
9970         {
9971             tng_data->output_endianness_swap_func_64 = 0;
9972         }
9973         else
9974         {
9975             tng_data->output_endianness_swap_func_64 =
9976             &tng_swap_byte_order_big_endian_64;
9977         }
9978         return(TNG_SUCCESS);
9979     }
9980     else if(endianness == TNG_LITTLE_ENDIAN)
9981     {
9982         if(tng_data->endianness_32 == TNG_LITTLE_ENDIAN_32)
9983         {
9984             tng_data->output_endianness_swap_func_32 = 0;
9985         }
9986         else
9987         {
9988             tng_data->output_endianness_swap_func_32 =
9989             &tng_swap_byte_order_little_endian_32;
9990         }
9991         if(tng_data->endianness_64 == TNG_LITTLE_ENDIAN_64)
9992         {
9993             tng_data->output_endianness_swap_func_64 = 0;
9994         }
9995         else
9996         {
9997             tng_data->output_endianness_swap_func_64 =
9998             &tng_swap_byte_order_little_endian_64;
9999         }
10000         return(TNG_SUCCESS);
10001     }
10002
10003     /* If the specified endianness is neither big nor little endian return a
10004      * failure. */
10005     return(TNG_FAILURE);
10006 }
10007
10008 tng_function_status DECLSPECDLLEXPORT tng_first_program_name_get
10009                     (const tng_trajectory_t tng_data,
10010                      char *name, const int max_len)
10011 {
10012     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10013     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10014
10015     strncpy(name, tng_data->first_program_name, max_len - 1);
10016     name[max_len - 1] = 0;
10017
10018     if(strlen(tng_data->first_program_name) > (unsigned int)max_len - 1)
10019     {
10020         return(TNG_FAILURE);
10021     }
10022     return(TNG_SUCCESS);
10023 }
10024
10025 tng_function_status DECLSPECDLLEXPORT tng_first_program_name_set(tng_trajectory_t tng_data,
10026                                                                  const char *new_name)
10027 {
10028     unsigned int len;
10029
10030     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10031     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10032
10033     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10034
10035     if(tng_data->first_program_name && strlen(tng_data->first_program_name) < len)
10036     {
10037         free(tng_data->first_program_name);
10038         tng_data->first_program_name = 0;
10039     }
10040     if(!tng_data->first_program_name)
10041     {
10042         tng_data->first_program_name = malloc(len);
10043         if(!tng_data->first_program_name)
10044         {
10045             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10046                    __FILE__, __LINE__);
10047             return(TNG_CRITICAL);
10048         }
10049     }
10050
10051     strncpy(tng_data->first_program_name, new_name, len);
10052
10053     return(TNG_SUCCESS);
10054 }
10055
10056 tng_function_status DECLSPECDLLEXPORT tng_last_program_name_get
10057                     (const tng_trajectory_t tng_data,
10058                      char *name, const int max_len)
10059 {
10060     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10061     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10062
10063     strncpy(name, tng_data->last_program_name, max_len - 1);
10064     name[max_len - 1] = 0;
10065
10066     if(strlen(tng_data->last_program_name) > (unsigned int)max_len - 1)
10067     {
10068         return(TNG_FAILURE);
10069     }
10070     return(TNG_SUCCESS);
10071 }
10072
10073 tng_function_status DECLSPECDLLEXPORT tng_last_program_name_set
10074                     (tng_trajectory_t tng_data,
10075                      const char *new_name)
10076 {
10077     unsigned int len;
10078
10079     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10080     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10081
10082     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10083
10084     if(tng_data->last_program_name && strlen(tng_data->last_program_name) < len)
10085     {
10086         free(tng_data->last_program_name);
10087         tng_data->last_program_name = 0;
10088     }
10089     if(!tng_data->last_program_name)
10090     {
10091         tng_data->last_program_name = malloc(len);
10092         if(!tng_data->last_program_name)
10093         {
10094             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10095                    __FILE__, __LINE__);
10096             return(TNG_CRITICAL);
10097         }
10098     }
10099
10100     strncpy(tng_data->last_program_name, new_name, len);
10101
10102     return(TNG_SUCCESS);
10103 }
10104
10105 tng_function_status DECLSPECDLLEXPORT tng_first_user_name_get
10106                     (const tng_trajectory_t tng_data,
10107                      char *name, const int max_len)
10108 {
10109     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10110     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10111
10112     strncpy(name, tng_data->first_user_name, max_len - 1);
10113     name[max_len - 1] = 0;
10114
10115     if(strlen(tng_data->first_user_name) > (unsigned int)max_len - 1)
10116     {
10117         return(TNG_FAILURE);
10118     }
10119     return(TNG_SUCCESS);
10120 }
10121
10122 tng_function_status DECLSPECDLLEXPORT tng_first_user_name_set
10123                     (tng_trajectory_t tng_data,
10124                      const char *new_name)
10125 {
10126     unsigned int len;
10127
10128     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10129     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10130
10131     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10132
10133     /* If the currently stored string length is not enough to store the new
10134      * string it is freed and reallocated. */
10135     if(tng_data->first_user_name && strlen(tng_data->first_user_name) < len)
10136     {
10137         free(tng_data->first_user_name);
10138         tng_data->first_user_name = 0;
10139     }
10140     if(!tng_data->first_user_name)
10141     {
10142         tng_data->first_user_name = malloc(len);
10143         if(!tng_data->first_user_name)
10144         {
10145             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10146                    __FILE__, __LINE__);
10147             return(TNG_CRITICAL);
10148         }
10149     }
10150
10151     strncpy(tng_data->first_user_name, new_name, len);
10152
10153     return(TNG_SUCCESS);
10154 }
10155
10156 tng_function_status DECLSPECDLLEXPORT tng_last_user_name_get
10157                     (const tng_trajectory_t tng_data,
10158                      char *name, const int max_len)
10159 {
10160     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10161     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10162
10163     strncpy(name, tng_data->last_user_name, max_len - 1);
10164     name[max_len - 1] = 0;
10165
10166     if(strlen(tng_data->last_user_name) > (unsigned int)max_len - 1)
10167     {
10168         return(TNG_FAILURE);
10169     }
10170     return(TNG_SUCCESS);
10171 }
10172
10173 tng_function_status DECLSPECDLLEXPORT tng_last_user_name_set
10174                     (tng_trajectory_t tng_data,
10175                      const char *new_name)
10176 {
10177     unsigned int len;
10178
10179     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10180     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10181
10182     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10183
10184     /* If the currently stored string length is not enough to store the new
10185      * string it is freed and reallocated. */
10186     if(tng_data->last_user_name && strlen(tng_data->last_user_name) < len)
10187     {
10188         free(tng_data->last_user_name);
10189         tng_data->last_user_name = 0;
10190     }
10191     if(!tng_data->last_user_name)
10192     {
10193         tng_data->last_user_name = malloc(len);
10194         if(!tng_data->last_user_name)
10195         {
10196             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10197                    __FILE__, __LINE__);
10198             return(TNG_CRITICAL);
10199         }
10200     }
10201
10202     strncpy(tng_data->last_user_name, new_name, len);
10203
10204     return(TNG_SUCCESS);
10205 }
10206
10207 tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_get
10208                     (const tng_trajectory_t tng_data,
10209                      char *name, const int max_len)
10210 {
10211     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10212     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10213
10214     strncpy(name, tng_data->first_computer_name, max_len - 1);
10215     name[max_len - 1] = 0;
10216
10217     if(strlen(tng_data->first_computer_name) > (unsigned int)max_len - 1)
10218     {
10219         return(TNG_FAILURE);
10220     }
10221     return(TNG_SUCCESS);
10222 }
10223
10224 tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_set
10225                     (tng_trajectory_t tng_data,
10226                      const char *new_name)
10227 {
10228     unsigned int len;
10229
10230     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10231     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10232
10233     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10234
10235     /* If the currently stored string length is not enough to store the new
10236      * string it is freed and reallocated. */
10237     if(tng_data->first_computer_name && strlen(tng_data->first_computer_name) < len)
10238     {
10239         free(tng_data->first_computer_name);
10240         tng_data->first_computer_name = 0;
10241     }
10242     if(!tng_data->first_computer_name)
10243     {
10244         tng_data->first_computer_name = malloc(len);
10245         if(!tng_data->first_computer_name)
10246         {
10247             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10248                    __FILE__, __LINE__);
10249             return(TNG_CRITICAL);
10250         }
10251     }
10252
10253     strncpy(tng_data->first_computer_name, new_name, len);
10254
10255     return(TNG_SUCCESS);
10256 }
10257
10258 tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_get
10259                     (const tng_trajectory_t tng_data,
10260                      char *name, const int max_len)
10261 {
10262     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10263     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10264
10265     strncpy(name, tng_data->last_computer_name, max_len - 1);
10266     name[max_len - 1] = 0;
10267
10268     if(strlen(tng_data->last_computer_name) > (unsigned int)max_len - 1)
10269     {
10270         return(TNG_FAILURE);
10271     }
10272     return(TNG_SUCCESS);
10273 }
10274
10275 tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_set
10276                     (tng_trajectory_t tng_data,
10277                      const char *new_name)
10278 {
10279     unsigned int len;
10280
10281     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10282     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10283
10284     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10285
10286     /* If the currently stored string length is not enough to store the new
10287      * string it is freed and reallocated. */
10288     if(tng_data->last_computer_name && strlen(tng_data->last_computer_name) <
10289         len)
10290     {
10291         free(tng_data->last_computer_name);
10292         tng_data->last_computer_name = 0;
10293     }
10294     if(!tng_data->last_computer_name)
10295     {
10296         tng_data->last_computer_name = malloc(len);
10297         if(!tng_data->last_computer_name)
10298         {
10299             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10300                    __FILE__, __LINE__);
10301             return(TNG_CRITICAL);
10302         }
10303     }
10304
10305     strncpy(tng_data->last_computer_name, new_name, len);
10306
10307     return(TNG_SUCCESS);
10308 }
10309
10310 tng_function_status DECLSPECDLLEXPORT tng_first_signature_get
10311                     (const tng_trajectory_t tng_data,
10312                      char *signature, const int max_len)
10313 {
10314     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10315     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
10316
10317     strncpy(signature, tng_data->first_pgp_signature, max_len - 1);
10318     signature[max_len - 1] = 0;
10319
10320     if(strlen(tng_data->first_pgp_signature) > (unsigned int)max_len - 1)
10321     {
10322         return(TNG_FAILURE);
10323     }
10324     return(TNG_SUCCESS);
10325 }
10326
10327 tng_function_status DECLSPECDLLEXPORT tng_first_signature_set
10328                     (tng_trajectory_t tng_data,
10329                      const char *signature)
10330 {
10331     unsigned int len;
10332
10333     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10334     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
10335
10336     len = tng_min_i((int)strlen(signature) + 1, TNG_MAX_STR_LEN);
10337
10338     /* If the currently stored string length is not enough to store the new
10339      * string it is freed and reallocated. */
10340     if(tng_data->first_pgp_signature && strlen(tng_data->first_pgp_signature) <
10341         len)
10342     {
10343         free(tng_data->first_pgp_signature);
10344         tng_data->first_pgp_signature = 0;
10345     }
10346     if(!tng_data->first_pgp_signature)
10347     {
10348         tng_data->first_pgp_signature = malloc(len);
10349         if(!tng_data->first_pgp_signature)
10350         {
10351             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10352                    __FILE__, __LINE__);
10353             return(TNG_CRITICAL);
10354         }
10355     }
10356
10357     strncpy(tng_data->first_pgp_signature, signature, len);
10358
10359     return(TNG_SUCCESS);
10360 }
10361
10362 tng_function_status DECLSPECDLLEXPORT tng_last_signature_get
10363                     (const tng_trajectory_t tng_data,
10364                      char *signature, const int max_len)
10365 {
10366     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10367     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
10368
10369     strncpy(signature, tng_data->last_pgp_signature, max_len - 1);
10370     signature[max_len - 1] = 0;
10371
10372     if(strlen(tng_data->last_pgp_signature) > (unsigned int)max_len - 1)
10373     {
10374         return(TNG_FAILURE);
10375     }
10376     return(TNG_SUCCESS);
10377 }
10378
10379 tng_function_status DECLSPECDLLEXPORT tng_last_signature_set
10380                     (tng_trajectory_t tng_data,
10381                      const char *signature)
10382 {
10383     unsigned int len;
10384
10385     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10386     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
10387
10388     len = tng_min_i((int)strlen(signature) + 1, TNG_MAX_STR_LEN);
10389
10390     /* If the currently stored string length is not enough to store the new
10391      * string it is freed and reallocated. */
10392     if(tng_data->last_pgp_signature && strlen(tng_data->last_pgp_signature) <
10393         len)
10394     {
10395         free(tng_data->last_pgp_signature);
10396         tng_data->last_pgp_signature = 0;
10397     }
10398     if(!tng_data->last_pgp_signature)
10399     {
10400         tng_data->last_pgp_signature = malloc(len);
10401         if(!tng_data->last_pgp_signature)
10402         {
10403             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10404                    __FILE__, __LINE__);
10405             return(TNG_CRITICAL);
10406         }
10407     }
10408
10409     strncpy(tng_data->last_pgp_signature, signature, len);
10410
10411     return(TNG_SUCCESS);
10412 }
10413
10414 tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_get
10415                     (const tng_trajectory_t tng_data,
10416                      char *name, const int max_len)
10417 {
10418     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10419     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10420
10421     strncpy(name, tng_data->forcefield_name, max_len - 1);
10422     name[max_len - 1] = 0;
10423
10424     if(strlen(tng_data->forcefield_name) > (unsigned int)max_len - 1)
10425     {
10426         return(TNG_FAILURE);
10427     }
10428     return(TNG_SUCCESS);
10429 }
10430
10431 tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_set
10432                     (tng_trajectory_t tng_data,
10433                      const char *new_name)
10434 {
10435     unsigned int len;
10436
10437     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10438     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10439
10440     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10441
10442     /* If the currently stored string length is not enough to store the new
10443      * string it is freed and reallocated. */
10444     if(tng_data->forcefield_name && strlen(tng_data->forcefield_name) < len)
10445     {
10446         free(tng_data->forcefield_name);
10447         tng_data->forcefield_name = 0;
10448     }
10449     if(!tng_data->forcefield_name)
10450     {
10451         tng_data->forcefield_name = malloc(len);
10452         if(!tng_data->forcefield_name)
10453         {
10454             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10455                    __FILE__, __LINE__);
10456             return(TNG_CRITICAL);
10457         }
10458     }
10459
10460     strncpy(tng_data->forcefield_name, new_name, len);
10461
10462     return(TNG_SUCCESS);
10463 }
10464
10465 tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_get
10466                     (const tng_trajectory_t tng_data,
10467                      int64_t *len)
10468 {
10469     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10470     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
10471
10472     *len = tng_data->medium_stride_length;
10473
10474     return(TNG_SUCCESS);
10475 }
10476
10477 tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_set
10478                     (tng_trajectory_t tng_data,
10479                      const int64_t len)
10480 {
10481     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10482
10483     if(len >= tng_data->long_stride_length)
10484     {
10485         return(TNG_FAILURE);
10486     }
10487     tng_data->medium_stride_length = len;
10488
10489     return(TNG_SUCCESS);
10490 }
10491
10492 tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_get
10493                 (const tng_trajectory_t tng_data,
10494                  int64_t *len)
10495 {
10496     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10497     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
10498
10499     *len = tng_data->long_stride_length;
10500
10501     return(TNG_SUCCESS);
10502 }
10503
10504 tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_set
10505                 (tng_trajectory_t tng_data,
10506                  const int64_t len)
10507 {
10508     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10509
10510     if(len <= tng_data->medium_stride_length)
10511     {
10512         return(TNG_FAILURE);
10513     }
10514     tng_data->long_stride_length = len;
10515
10516     return(TNG_SUCCESS);
10517 }
10518
10519 tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_get
10520                 (const tng_trajectory_t tng_data,
10521                  double *time)
10522 {
10523     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10524     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
10525
10526     *time = tng_data->time_per_frame;
10527
10528     return(TNG_SUCCESS);
10529 }
10530
10531 tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_set
10532                 (tng_trajectory_t tng_data,
10533                  const double time)
10534 {
10535     tng_trajectory_frame_set_t frame_set;
10536
10537     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10538     TNG_ASSERT(time >= 0, "TNG library: The time per frame must be >= 0.");
10539
10540     if(fabs(time - tng_data->time_per_frame) < 0.00001)
10541     {
10542         return(TNG_SUCCESS);
10543     }
10544
10545     frame_set = &tng_data->current_trajectory_frame_set;
10546
10547     /* If the current frame set is not finished write it to disk before
10548        changing time per frame. */
10549     if(tng_data->time_per_frame > 0 && frame_set->n_unwritten_frames > 0)
10550     {
10551         frame_set->n_frames = frame_set->n_unwritten_frames;
10552         tng_frame_set_write(tng_data, TNG_USE_HASH);
10553     }
10554     tng_data->time_per_frame = time;
10555
10556     return(TNG_SUCCESS);
10557 }
10558
10559 tng_function_status DECLSPECDLLEXPORT tng_input_file_len_get
10560                     (const tng_trajectory_t tng_data,
10561                      int64_t *len)
10562 {
10563     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10564     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
10565
10566     *len = tng_data->input_file_len;
10567
10568     return(TNG_SUCCESS);
10569 }
10570
10571 tng_function_status DECLSPECDLLEXPORT tng_num_frames_get
10572                     (const tng_trajectory_t tng_data,
10573                      int64_t *n)
10574 {
10575     tng_gen_block_t block;
10576     tng_function_status stat;
10577     long file_pos;
10578     int64_t last_file_pos, first_frame, n_frames;
10579
10580     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10581     TNG_ASSERT(tng_data->input_file, "TNG library: An input file must be open to find the next frame set");
10582     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10583
10584     file_pos = ftell(tng_data->input_file);
10585     last_file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
10586
10587     if(last_file_pos <= 0)
10588     {
10589         return(TNG_FAILURE);
10590     }
10591
10592     tng_block_init(&block);
10593     fseek(tng_data->input_file,
10594           (long)last_file_pos,
10595           SEEK_SET);
10596     /* Read block headers first to see that a frame set block is found. */
10597     stat = tng_block_header_read(tng_data, block);
10598     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10599     {
10600         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", last_file_pos,
10601                 __FILE__, __LINE__);
10602         tng_block_destroy(&block);
10603         return(TNG_FAILURE);
10604     }
10605     tng_block_destroy(&block);
10606
10607     if(fread(&first_frame, sizeof(int64_t), 1, tng_data->input_file) == 0)
10608     {
10609         fprintf(stderr, "TNG library: Cannot read first frame of frame set. %s: %d\n",
10610                __FILE__, __LINE__);
10611         return(TNG_CRITICAL);
10612     }
10613     if(fread(&n_frames, sizeof(int64_t), 1, tng_data->input_file) == 0)
10614     {
10615         fprintf(stderr, "TNG library: Cannot read n frames of frame set. %s: %d\n",
10616                __FILE__, __LINE__);
10617         return(TNG_CRITICAL);
10618     }
10619     fseek(tng_data->input_file, file_pos, SEEK_SET);
10620
10621     *n = first_frame + n_frames;
10622
10623     return(TNG_SUCCESS);
10624 }
10625
10626 tng_function_status DECLSPECDLLEXPORT tng_compression_precision_get
10627                 (const tng_trajectory_t tng_data,
10628                  double *precision)
10629 {
10630     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10631
10632     *precision = tng_data->compression_precision;
10633
10634     return(TNG_SUCCESS);
10635 }
10636
10637 tng_function_status DECLSPECDLLEXPORT tng_compression_precision_set
10638                 (tng_trajectory_t tng_data,
10639                  const double precision)
10640 {
10641     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10642
10643     tng_data->compression_precision = precision;
10644
10645     return(TNG_SUCCESS);
10646 }
10647
10648 tng_function_status DECLSPECDLLEXPORT tng_implicit_num_particles_set
10649                 (tng_trajectory_t tng_data,
10650                  const int64_t n)
10651 {
10652     tng_molecule_t mol;
10653     tng_chain_t chain;
10654     tng_residue_t res;
10655     tng_atom_t atom;
10656     tng_function_status stat;
10657     int64_t diff, n_mod, n_impl;
10658
10659     TNG_ASSERT(n >= 0, "TNG library: The number of molecules must be >= 0");
10660
10661     diff = n - tng_data->n_particles;
10662
10663     stat = tng_molecule_find(tng_data, "TNG_IMPLICIT_MOL", -1, &mol);
10664     if(stat == TNG_SUCCESS)
10665     {
10666         if(tng_molecule_cnt_get(tng_data, mol, &n_impl) != TNG_SUCCESS)
10667         {
10668             fprintf(stderr, "TNG library: Cannot get the number of implicit molecules. %s: %d\n",
10669                     __FILE__, __LINE__);
10670             return(TNG_FAILURE);
10671         }
10672         diff -= n_impl * mol->n_atoms;
10673     }
10674
10675     if(diff == 0)
10676     {
10677         if(stat == TNG_SUCCESS)
10678         {
10679             stat = tng_molecule_cnt_set(tng_data, mol, 0);
10680             return(stat);
10681         }
10682         return(TNG_SUCCESS);
10683     }
10684     else if(diff < 0)
10685     {
10686         fprintf(stderr, "TNG library: Already more actual particles than requested implicit ");
10687         fprintf(stderr, "particle count.\n");
10688         fprintf(stderr, "TNG library: Cannot set implicit particle count. %s: %d\n",
10689                 __FILE__, __LINE__);
10690         /* FIXME: Should we set the count of all other molecules to 0 and add
10691          * implicit molecules? */
10692         return(TNG_FAILURE);
10693     }
10694     if(stat != TNG_SUCCESS)
10695     {
10696         stat = tng_molecule_add(tng_data,
10697                                 "TNG_IMPLICIT_MOL",
10698                                 &mol);
10699         if(stat != TNG_SUCCESS)
10700         {
10701             return(stat);
10702         }
10703         stat = tng_molecule_chain_add(tng_data, mol, "", &chain);
10704         if(stat != TNG_SUCCESS)
10705         {
10706             return(stat);
10707         }
10708         stat = tng_chain_residue_add(tng_data, chain, "", &res);
10709         if(stat != TNG_SUCCESS)
10710         {
10711             return(stat);
10712         }
10713         stat = tng_residue_atom_add(tng_data, res, "", "", &atom);
10714         if(stat != TNG_SUCCESS)
10715         {
10716             return(stat);
10717         }
10718     }
10719     else
10720     {
10721         if(mol->n_atoms > 1)
10722         {
10723             n_mod = diff % mol->n_atoms;
10724             if(n_mod != 0)
10725             {
10726                 fprintf(stderr, "TNG library: Number of atoms in implicit molecule ");
10727                 fprintf(stderr, "not compatible with requested implicit particle cnt.\n");
10728                 fprintf(stderr, "TNG library: Cannot set implicit particle count. %s: %d\n",
10729                         __FILE__, __LINE__);
10730                 return(TNG_FAILURE);
10731             }
10732             diff /= mol->n_atoms;
10733         }
10734     }
10735     stat = tng_molecule_cnt_set(tng_data, mol, diff);
10736
10737     return(stat);
10738 }
10739
10740 tng_function_status DECLSPECDLLEXPORT tng_num_particles_get
10741                 (const tng_trajectory_t tng_data,
10742                  int64_t *n)
10743 {
10744     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10745     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10746
10747     if(tng_data->var_num_atoms_flag == TNG_CONSTANT_N_ATOMS)
10748     {
10749         *n = tng_data->n_particles;
10750     }
10751     else
10752     {
10753         *n = tng_data->current_trajectory_frame_set.n_particles;
10754     }
10755
10756     return(TNG_SUCCESS);
10757 }
10758
10759 tng_function_status DECLSPECDLLEXPORT tng_num_particles_variable_get
10760                 (const tng_trajectory_t tng_data,
10761                  char *variable)
10762 {
10763     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10764     TNG_ASSERT(variable, "TNG library: variable must not be a NULL pointer");
10765
10766     *variable = tng_data->var_num_atoms_flag;
10767
10768     return(TNG_SUCCESS);
10769 }
10770
10771 tng_function_status DECLSPECDLLEXPORT tng_num_molecule_types_get
10772                     (const tng_trajectory_t tng_data,
10773                      int64_t *n)
10774 {
10775     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10776     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10777
10778     *n = tng_data->n_molecules;
10779
10780     return(TNG_SUCCESS);
10781 }
10782
10783 tng_function_status DECLSPECDLLEXPORT tng_num_molecules_get
10784                     (const tng_trajectory_t tng_data,
10785                      int64_t *n)
10786 {
10787     int64_t *cnt_list = 0, cnt = 0, i;
10788
10789     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10790     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10791
10792     tng_molecule_cnt_list_get(tng_data, &cnt_list);
10793
10794     if(!cnt_list)
10795     {
10796         return(TNG_FAILURE);
10797     }
10798
10799     for(i = tng_data->n_molecules; i --;)
10800     {
10801         cnt += cnt_list[i];
10802     }
10803
10804     *n = cnt;
10805
10806     return(TNG_SUCCESS);
10807 }
10808
10809 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_list_get
10810                 (const tng_trajectory_t tng_data,
10811                  int64_t **mol_cnt_list)
10812 {
10813     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10814
10815     if(tng_data->var_num_atoms_flag)
10816     {
10817         *mol_cnt_list = tng_data->current_trajectory_frame_set.
10818                        molecule_cnt_list;
10819     }
10820     else
10821     {
10822         *mol_cnt_list = tng_data->molecule_cnt_list;
10823     }
10824     if(*mol_cnt_list == 0)
10825     {
10826         return(TNG_FAILURE);
10827     }
10828     return(TNG_SUCCESS);
10829 }
10830
10831 tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_get
10832                 (const tng_trajectory_t tng_data,
10833                  int64_t *exp)
10834 {
10835     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10836     TNG_ASSERT(exp, "TNG library: exp must not be a NULL pointer");
10837
10838     *exp = tng_data->distance_unit_exponential;
10839
10840     return(TNG_SUCCESS);
10841 }
10842
10843 tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_set
10844                 (const tng_trajectory_t tng_data,
10845                  const int64_t exp)
10846 {
10847     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10848
10849     tng_data->distance_unit_exponential = exp;
10850
10851     return(TNG_SUCCESS);
10852 }
10853
10854 tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_get
10855                 (const tng_trajectory_t tng_data,
10856                  int64_t *n)
10857 {
10858     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10859     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10860
10861     *n = tng_data->frame_set_n_frames;
10862
10863     return(TNG_SUCCESS);
10864 }
10865
10866 tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_set
10867                 (const tng_trajectory_t tng_data,
10868                  const int64_t n)
10869 {
10870     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10871
10872     tng_data->frame_set_n_frames = n;
10873
10874     return(TNG_SUCCESS);
10875 }
10876
10877 tng_function_status DECLSPECDLLEXPORT tng_num_frame_sets_get
10878                 (const tng_trajectory_t tng_data,
10879                  int64_t *n)
10880 {
10881     int64_t long_stride_length, medium_stride_length;
10882     long file_pos, orig_frame_set_file_pos;
10883     tng_trajectory_frame_set_t frame_set;
10884     struct tng_trajectory_frame_set   orig_frame_set;
10885     tng_gen_block_t block;
10886     tng_function_status stat;
10887     int64_t cnt = 0;
10888
10889     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10890     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10891
10892     orig_frame_set = tng_data->current_trajectory_frame_set;
10893
10894     frame_set = &tng_data->current_trajectory_frame_set;
10895
10896     orig_frame_set_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
10897     file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
10898
10899     tng_block_init(&block);
10900     fseek(tng_data->input_file,
10901           file_pos,
10902           SEEK_SET);
10903     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
10904     /* Read block headers first to see what block is found. */
10905     stat = tng_block_header_read(tng_data, block);
10906     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10907     {
10908         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n", file_pos,
10909                 __FILE__, __LINE__);
10910         tng_block_destroy(&block);
10911         return(TNG_CRITICAL);
10912     }
10913
10914     if(tng_block_read_next(tng_data, block,
10915                         TNG_SKIP_HASH) != TNG_SUCCESS)
10916     {
10917         tng_block_destroy(&block);
10918         return(TNG_CRITICAL);
10919     }
10920
10921     ++cnt;
10922
10923     long_stride_length = tng_data->long_stride_length;
10924     medium_stride_length = tng_data->medium_stride_length;
10925
10926     /* Take long steps forward until a long step forward would be too long or
10927      * the last frame set is found */
10928     file_pos = (long)frame_set->long_stride_next_frame_set_file_pos;
10929     while(file_pos > 0)
10930     {
10931         if(file_pos > 0)
10932         {
10933             cnt += long_stride_length;
10934             fseek(tng_data->input_file, file_pos, SEEK_SET);
10935             /* Read block headers first to see what block is found. */
10936             stat = tng_block_header_read(tng_data, block);
10937             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10938             {
10939                 fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
10940                        file_pos, __FILE__, __LINE__);
10941                 tng_block_destroy(&block);
10942                 return(TNG_CRITICAL);
10943             }
10944
10945             if(tng_block_read_next(tng_data, block,
10946                                 TNG_SKIP_HASH) != TNG_SUCCESS)
10947             {
10948                 tng_block_destroy(&block);
10949                 return(TNG_CRITICAL);
10950             }
10951         }
10952         file_pos = (long)frame_set->long_stride_next_frame_set_file_pos;
10953     }
10954
10955     /* Take medium steps forward until a medium step forward would be too long
10956      * or the last frame set is found */
10957     file_pos = (long)frame_set->medium_stride_next_frame_set_file_pos;
10958     while(file_pos > 0)
10959     {
10960         if(file_pos > 0)
10961         {
10962             cnt += medium_stride_length;
10963             fseek(tng_data->input_file,
10964                   file_pos,
10965                   SEEK_SET);
10966             /* Read block headers first to see what block is found. */
10967             stat = tng_block_header_read(tng_data, block);
10968             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10969             {
10970                 fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
10971                        file_pos, __FILE__, __LINE__);
10972                 tng_block_destroy(&block);
10973                 return(TNG_CRITICAL);
10974             }
10975
10976             if(tng_block_read_next(tng_data, block,
10977                                 TNG_SKIP_HASH) != TNG_SUCCESS)
10978             {
10979                 tng_block_destroy(&block);
10980                 return(TNG_CRITICAL);
10981             }
10982         }
10983         file_pos = (long)frame_set->medium_stride_next_frame_set_file_pos;
10984     }
10985
10986     /* Take one step forward until the last frame set is found */
10987     file_pos = (long)frame_set->next_frame_set_file_pos;
10988     while(file_pos > 0)
10989     {
10990         if(file_pos > 0)
10991         {
10992             ++cnt;
10993             fseek(tng_data->input_file,
10994                   file_pos,
10995                   SEEK_SET);
10996             /* Read block headers first to see what block is found. */
10997             stat = tng_block_header_read(tng_data, block);
10998             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10999             {
11000                 fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
11001                        file_pos, __FILE__, __LINE__);
11002                 tng_block_destroy(&block);
11003                 return(TNG_CRITICAL);
11004             }
11005
11006             if(tng_block_read_next(tng_data, block,
11007                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11008             {
11009                 tng_block_destroy(&block);
11010                 return(TNG_CRITICAL);
11011             }
11012         }
11013         file_pos = (long)frame_set->next_frame_set_file_pos;
11014     }
11015
11016     tng_block_destroy(&block);
11017
11018     *n = tng_data->n_trajectory_frame_sets = cnt;
11019
11020     *frame_set = orig_frame_set;
11021
11022     fseek(tng_data->input_file,
11023           (long)tng_data->first_trajectory_frame_set_input_file_pos,
11024           SEEK_SET);
11025
11026     tng_data->current_trajectory_frame_set_input_file_pos = orig_frame_set_file_pos;
11027
11028     return(TNG_SUCCESS);
11029 }
11030
11031 tng_function_status DECLSPECDLLEXPORT tng_current_frame_set_get
11032                 (const tng_trajectory_t tng_data,
11033                  tng_trajectory_frame_set_t *frame_set_p)
11034 {
11035     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11036
11037     *frame_set_p = &tng_data->current_trajectory_frame_set;
11038
11039     return(TNG_SUCCESS);
11040 }
11041
11042 tng_function_status DECLSPECDLLEXPORT tng_frame_set_nr_find
11043                 (tng_trajectory_t tng_data,
11044                  const int64_t nr)
11045 {
11046     int64_t long_stride_length, medium_stride_length;
11047     int64_t file_pos, curr_nr = 0, n_frame_sets;
11048     tng_trajectory_frame_set_t frame_set;
11049     tng_gen_block_t block;
11050     tng_function_status stat;
11051
11052     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11053     TNG_ASSERT(nr >= 0, "The frame set number (nr) must be >= 0");
11054
11055     frame_set = &tng_data->current_trajectory_frame_set;
11056
11057     stat = tng_num_frame_sets_get(tng_data, &n_frame_sets);
11058
11059     if(stat != TNG_SUCCESS)
11060     {
11061         return(stat);
11062     }
11063
11064     if(nr >= n_frame_sets)
11065     {
11066         return(TNG_FAILURE);
11067     }
11068
11069     long_stride_length = tng_data->long_stride_length;
11070     medium_stride_length = tng_data->medium_stride_length;
11071
11072     /* FIXME: The frame set number of the current frame set is not stored */
11073
11074     if(nr < n_frame_sets - 1 - nr)
11075     {
11076         /* Start from the beginning */
11077         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
11078     }
11079     else
11080     {
11081         /* Start from the end */
11082         file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
11083         curr_nr = n_frame_sets - 1;
11084     }
11085     if(file_pos <= 0)
11086     {
11087         return(TNG_FAILURE);
11088     }
11089
11090     tng_block_init(&block);
11091     fseek(tng_data->input_file,
11092           (long)file_pos,
11093           SEEK_SET);
11094     tng_data->current_trajectory_frame_set_input_file_pos = (long)file_pos;
11095     /* Read block headers first to see what block is found. */
11096     stat = tng_block_header_read(tng_data, block);
11097     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11098     {
11099         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", file_pos,
11100                 __FILE__, __LINE__);
11101         tng_block_destroy(&block);
11102         return(TNG_CRITICAL);
11103     }
11104
11105     if(tng_block_read_next(tng_data, block,
11106                         TNG_SKIP_HASH) != TNG_SUCCESS)
11107     {
11108         tng_block_destroy(&block);
11109         return(TNG_CRITICAL);
11110     }
11111
11112     if(curr_nr == nr)
11113     {
11114         tng_block_destroy(&block);
11115         return(TNG_SUCCESS);
11116     }
11117
11118     file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11119
11120     /* Take long steps forward until a long step forward would be too long or
11121      * the right frame set is found */
11122     while(file_pos > 0 && curr_nr + long_stride_length <= nr)
11123     {
11124         file_pos = frame_set->long_stride_next_frame_set_file_pos;
11125         if(file_pos > 0)
11126         {
11127             curr_nr += long_stride_length;
11128             fseek(tng_data->input_file, (long)file_pos, SEEK_SET);
11129             /* Read block headers first to see what block is found. */
11130             stat = tng_block_header_read(tng_data, block);
11131             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11132             {
11133                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11134                        file_pos,  __FILE__, __LINE__);
11135                 tng_block_destroy(&block);
11136                 return(TNG_CRITICAL);
11137             }
11138
11139             if(tng_block_read_next(tng_data, block,
11140                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11141             {
11142                 tng_block_destroy(&block);
11143                 return(TNG_CRITICAL);
11144             }
11145             if(curr_nr == nr)
11146             {
11147                 tng_block_destroy(&block);
11148                 return(TNG_SUCCESS);
11149             }
11150         }
11151     }
11152
11153     /* Take medium steps forward until a medium step forward would be too long
11154      * or the right frame set is found */
11155     while(file_pos > 0 && curr_nr + medium_stride_length <= nr)
11156     {
11157         file_pos = frame_set->medium_stride_next_frame_set_file_pos;
11158         if(file_pos > 0)
11159         {
11160             curr_nr += medium_stride_length;
11161             fseek(tng_data->input_file,
11162                   (long)file_pos,
11163                   SEEK_SET);
11164             /* Read block headers first to see what block is found. */
11165             stat = tng_block_header_read(tng_data, block);
11166             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11167             {
11168                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11169                        file_pos, __FILE__, __LINE__);
11170                 tng_block_destroy(&block);
11171                 return(TNG_CRITICAL);
11172             }
11173
11174             if(tng_block_read_next(tng_data, block,
11175                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11176             {
11177                 tng_block_destroy(&block);
11178                 return(TNG_CRITICAL);
11179             }
11180             if(curr_nr == nr)
11181             {
11182                 tng_block_destroy(&block);
11183                 return(TNG_SUCCESS);
11184             }
11185         }
11186     }
11187
11188     /* Take one step forward until the right frame set is found */
11189     while(file_pos > 0 && curr_nr < nr)
11190     {
11191         file_pos = frame_set->next_frame_set_file_pos;
11192
11193         if(file_pos > 0)
11194         {
11195             ++curr_nr;
11196             fseek(tng_data->input_file,
11197                   (long)file_pos,
11198                   SEEK_SET);
11199             /* Read block headers first to see what block is found. */
11200             stat = tng_block_header_read(tng_data, block);
11201             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11202             {
11203                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11204                        file_pos, __FILE__, __LINE__);
11205                 tng_block_destroy(&block);
11206                 return(TNG_CRITICAL);
11207             }
11208
11209             if(tng_block_read_next(tng_data, block,
11210                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11211             {
11212                 tng_block_destroy(&block);
11213                 return(TNG_CRITICAL);
11214             }
11215             if(curr_nr == nr)
11216             {
11217                 tng_block_destroy(&block);
11218                 return(TNG_SUCCESS);
11219             }
11220         }
11221     }
11222
11223     /* Take long steps backward until a long step backward would be too long
11224      * or the right frame set is found */
11225     while(file_pos > 0 && curr_nr - long_stride_length >= nr)
11226     {
11227         file_pos = frame_set->long_stride_prev_frame_set_file_pos;
11228         if(file_pos > 0)
11229         {
11230             curr_nr -= long_stride_length;
11231             fseek(tng_data->input_file,
11232                   (long)file_pos,
11233                   SEEK_SET);
11234             /* Read block headers first to see what block is found. */
11235             stat = tng_block_header_read(tng_data, block);
11236             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11237             {
11238                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11239                        file_pos, __FILE__, __LINE__);
11240                 tng_block_destroy(&block);
11241                 return(TNG_CRITICAL);
11242             }
11243
11244             if(tng_block_read_next(tng_data, block,
11245                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11246             {
11247                 tng_block_destroy(&block);
11248                 return(TNG_CRITICAL);
11249             }
11250             if(curr_nr == nr)
11251             {
11252                 tng_block_destroy(&block);
11253                 return(TNG_SUCCESS);
11254             }
11255         }
11256     }
11257
11258     /* Take medium steps backward until a medium step backward would be too long
11259      * or the right frame set is found */
11260     while(file_pos > 0 && curr_nr - medium_stride_length >= nr)
11261     {
11262         file_pos = frame_set->medium_stride_prev_frame_set_file_pos;
11263         if(file_pos > 0)
11264         {
11265             curr_nr -= medium_stride_length;
11266             fseek(tng_data->input_file,
11267                   (long)file_pos,
11268                   SEEK_SET);
11269             /* Read block headers first to see what block is found. */
11270             stat = tng_block_header_read(tng_data, block);
11271             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11272             {
11273                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11274                        file_pos, __FILE__, __LINE__);
11275                 tng_block_destroy(&block);
11276                 return(TNG_CRITICAL);
11277             }
11278
11279             if(tng_block_read_next(tng_data, block,
11280                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11281             {
11282                 tng_block_destroy(&block);
11283                 return(TNG_CRITICAL);
11284             }
11285             if(curr_nr == nr)
11286             {
11287                 tng_block_destroy(&block);
11288                 return(TNG_SUCCESS);
11289             }
11290         }
11291     }
11292
11293     /* Take one step backward until the right frame set is found */
11294     while(file_pos > 0 && curr_nr > nr)
11295     {
11296         file_pos = frame_set->prev_frame_set_file_pos;
11297         if(file_pos > 0)
11298         {
11299             --curr_nr;
11300             fseek(tng_data->input_file,
11301                   (long)file_pos,
11302                   SEEK_SET);
11303             /* Read block headers first to see what block is found. */
11304             stat = tng_block_header_read(tng_data, block);
11305             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11306             {
11307                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11308                        file_pos, __FILE__, __LINE__);
11309                 tng_block_destroy(&block);
11310                 return(TNG_CRITICAL);
11311             }
11312
11313             if(tng_block_read_next(tng_data, block,
11314                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11315             {
11316                 tng_block_destroy(&block);
11317                 return(TNG_CRITICAL);
11318             }
11319             if(curr_nr == nr)
11320             {
11321                 tng_block_destroy(&block);
11322                 return(TNG_SUCCESS);
11323             }
11324         }
11325     }
11326
11327     /* If for some reason the current frame set is not yet found,
11328      * take one step forward until the right frame set is found */
11329     while(file_pos > 0 && curr_nr < nr)
11330     {
11331         file_pos = frame_set->next_frame_set_file_pos;
11332         if(file_pos > 0)
11333         {
11334             ++curr_nr;
11335             fseek(tng_data->input_file,
11336                   (long)file_pos,
11337                   SEEK_SET);
11338             /* Read block headers first to see what block is found. */
11339             stat = tng_block_header_read(tng_data, block);
11340             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11341             {
11342                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11343                        file_pos, __FILE__, __LINE__);
11344                 tng_block_destroy(&block);
11345                 return(TNG_CRITICAL);
11346             }
11347
11348             if(tng_block_read_next(tng_data, block,
11349                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11350             {
11351                 tng_block_destroy(&block);
11352                 return(TNG_CRITICAL);
11353             }
11354             if(curr_nr == nr)
11355             {
11356                 tng_block_destroy(&block);
11357                 return(TNG_SUCCESS);
11358             }
11359         }
11360     }
11361
11362     tng_block_destroy(&block);
11363     return(TNG_FAILURE);
11364 }
11365
11366 tng_function_status DECLSPECDLLEXPORT tng_frame_set_of_frame_find
11367                 (tng_trajectory_t tng_data,
11368                  const int64_t frame)
11369 {
11370     int64_t first_frame, last_frame, n_frames_per_frame_set;
11371     int64_t long_stride_length, medium_stride_length;
11372     int64_t file_pos, temp_frame, n_frames;
11373     tng_trajectory_frame_set_t frame_set;
11374     tng_gen_block_t block;
11375     tng_function_status stat;
11376
11377     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11378     TNG_ASSERT(frame >= 0, "TNG library: frame must be >= 0.");
11379
11380     frame_set = &tng_data->current_trajectory_frame_set;
11381
11382     tng_block_init(&block);
11383
11384     if(tng_data->current_trajectory_frame_set_input_file_pos < 0)
11385     {
11386         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
11387         fseek(tng_data->input_file,
11388                 (long)file_pos,
11389                 SEEK_SET);
11390         tng_data->current_trajectory_frame_set_input_file_pos = (long)file_pos;
11391         /* Read block headers first to see what block is found. */
11392         stat = tng_block_header_read(tng_data, block);
11393         if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11394         {
11395             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11396                     file_pos, __FILE__, __LINE__);
11397             tng_block_destroy(&block);
11398             return(TNG_CRITICAL);
11399         }
11400
11401         if(tng_block_read_next(tng_data, block,
11402                             TNG_SKIP_HASH) != TNG_SUCCESS)
11403         {
11404             tng_block_destroy(&block);
11405             return(TNG_CRITICAL);
11406         }
11407     }
11408
11409     first_frame = tng_max_i64(frame_set->first_frame, 0);
11410     last_frame = first_frame + frame_set->n_frames - 1;
11411     /* Is this the right frame set? */
11412     if(first_frame <= frame && frame <= last_frame)
11413     {
11414         tng_block_destroy(&block);
11415         return(TNG_SUCCESS);
11416     }
11417
11418     n_frames_per_frame_set = tng_data->frame_set_n_frames;
11419     long_stride_length = tng_data->long_stride_length;
11420     medium_stride_length = tng_data->medium_stride_length;
11421
11422     if(tng_first_frame_nr_of_next_frame_set_get(tng_data, &temp_frame) ==
11423        TNG_SUCCESS)
11424     {
11425         if(temp_frame - first_frame > n_frames_per_frame_set)
11426         {
11427             n_frames_per_frame_set = temp_frame - first_frame;
11428         }
11429     }
11430
11431     tng_num_frames_get(tng_data, &n_frames);
11432
11433     if(frame >= n_frames)
11434     {
11435         tng_block_destroy(&block);
11436         return(TNG_FAILURE);
11437     }
11438
11439     if(first_frame - frame >= frame ||
11440        frame - last_frame >
11441        tng_data->n_trajectory_frame_sets * n_frames_per_frame_set - frame)
11442     {
11443         /* Start from the beginning */
11444         if(first_frame - frame >= frame)
11445         {
11446             file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
11447
11448             if(file_pos <= 0)
11449             {
11450                 tng_block_destroy(&block);
11451                 return(TNG_FAILURE);
11452             }
11453         }
11454         /* Start from the end */
11455         else if(frame - first_frame > (n_frames - 1) - frame)
11456         {
11457             file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
11458
11459             /* If the last frame set position is not set start from the current
11460              * frame set, since it will be closer than the first frame set. */
11461         }
11462         /* Start from current */
11463         else
11464         {
11465             file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11466         }
11467
11468         if(file_pos > 0)
11469         {
11470             fseek(tng_data->input_file,
11471                   (long)file_pos,
11472                   SEEK_SET);
11473             tng_data->current_trajectory_frame_set_input_file_pos = (long)file_pos;
11474             /* Read block headers first to see what block is found. */
11475             stat = tng_block_header_read(tng_data, block);
11476             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11477             {
11478                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11479                        file_pos, __FILE__, __LINE__);
11480                 tng_block_destroy(&block);
11481                 return(TNG_CRITICAL);
11482             }
11483
11484             if(tng_block_read_next(tng_data, block,
11485                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11486             {
11487                 tng_block_destroy(&block);
11488                 return(TNG_CRITICAL);
11489             }
11490         }
11491     }
11492
11493     first_frame = tng_max_i64(frame_set->first_frame, 0);
11494     last_frame = first_frame + frame_set->n_frames - 1;
11495
11496     if(frame >= first_frame && frame <= last_frame)
11497     {
11498         tng_block_destroy(&block);
11499         return(TNG_SUCCESS);
11500     }
11501
11502     file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11503
11504     /* Take long steps forward until a long step forward would be too long or
11505      * the right frame set is found */
11506     while(file_pos > 0 && first_frame + long_stride_length *
11507           n_frames_per_frame_set <= frame)
11508     {
11509         file_pos = frame_set->long_stride_next_frame_set_file_pos;
11510         if(file_pos > 0)
11511         {
11512             fseek(tng_data->input_file, (long)file_pos, SEEK_SET);
11513             /* Read block headers first to see what block is found. */
11514             stat = tng_block_header_read(tng_data, block);
11515             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11516             {
11517                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11518                        file_pos, __FILE__, __LINE__);
11519                 tng_block_destroy(&block);
11520                 return(TNG_CRITICAL);
11521             }
11522
11523             if(tng_block_read_next(tng_data, block,
11524                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11525             {
11526                 tng_block_destroy(&block);
11527                 return(TNG_CRITICAL);
11528             }
11529         }
11530         first_frame = tng_max_i64(frame_set->first_frame, 0);
11531         last_frame = first_frame + frame_set->n_frames - 1;
11532         if(frame >= first_frame && frame <= last_frame)
11533         {
11534             tng_block_destroy(&block);
11535             return(TNG_SUCCESS);
11536         }
11537     }
11538
11539     /* Take medium steps forward until a medium step forward would be too long
11540      * or the right frame set is found */
11541     while(file_pos > 0 && first_frame + medium_stride_length *
11542           n_frames_per_frame_set <= frame)
11543     {
11544         file_pos = frame_set->medium_stride_next_frame_set_file_pos;
11545         if(file_pos > 0)
11546         {
11547             fseek(tng_data->input_file,
11548                   (long)file_pos,
11549                   SEEK_SET);
11550             /* Read block headers first to see what block is found. */
11551             stat = tng_block_header_read(tng_data, block);
11552             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11553             {
11554                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11555                        file_pos, __FILE__, __LINE__);
11556                 tng_block_destroy(&block);
11557                 return(TNG_CRITICAL);
11558             }
11559
11560             if(tng_block_read_next(tng_data, block,
11561                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11562             {
11563                 tng_block_destroy(&block);
11564                 return(TNG_CRITICAL);
11565             }
11566         }
11567         first_frame = tng_max_i64(frame_set->first_frame, 0);
11568         last_frame = first_frame + frame_set->n_frames - 1;
11569         if(frame >= first_frame && frame <= last_frame)
11570         {
11571             tng_block_destroy(&block);
11572             return(TNG_SUCCESS);
11573         }
11574     }
11575
11576     /* Take one step forward until the right frame set is found */
11577     while(file_pos > 0 && first_frame < frame && last_frame < frame)
11578     {
11579         file_pos = frame_set->next_frame_set_file_pos;
11580         if(file_pos > 0)
11581         {
11582             fseek(tng_data->input_file,
11583                   (long)file_pos,
11584                   SEEK_SET);
11585             /* Read block headers first to see what block is found. */
11586             stat = tng_block_header_read(tng_data, block);
11587             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11588             {
11589                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11590                        file_pos, __FILE__, __LINE__);
11591                 tng_block_destroy(&block);
11592                 return(TNG_CRITICAL);
11593             }
11594
11595             if(tng_block_read_next(tng_data, block,
11596                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11597             {
11598                 tng_block_destroy(&block);
11599                 return(TNG_CRITICAL);
11600             }
11601         }
11602         first_frame = tng_max_i64(frame_set->first_frame, 0);
11603         last_frame = first_frame + frame_set->n_frames - 1;
11604         if(frame >= first_frame && frame <= last_frame)
11605         {
11606             tng_block_destroy(&block);
11607             return(TNG_SUCCESS);
11608         }
11609     }
11610
11611     /* Take long steps backward until a long step backward would be too long
11612      * or the right frame set is found */
11613     while(file_pos > 0 && first_frame - long_stride_length *
11614           n_frames_per_frame_set >= frame)
11615     {
11616         file_pos = frame_set->long_stride_prev_frame_set_file_pos;
11617         if(file_pos > 0)
11618         {
11619             fseek(tng_data->input_file,
11620                   (long)file_pos,
11621                   SEEK_SET);
11622             /* Read block headers first to see what block is found. */
11623             stat = tng_block_header_read(tng_data, block);
11624             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11625             {
11626                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11627                        file_pos, __FILE__, __LINE__);
11628                 tng_block_destroy(&block);
11629                 return(TNG_CRITICAL);
11630             }
11631
11632             if(tng_block_read_next(tng_data, block,
11633                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11634             {
11635                 tng_block_destroy(&block);
11636                 return(TNG_CRITICAL);
11637             }
11638         }
11639         first_frame = tng_max_i64(frame_set->first_frame, 0);
11640         last_frame = first_frame + frame_set->n_frames - 1;
11641         if(frame >= first_frame && frame <= last_frame)
11642         {
11643             tng_block_destroy(&block);
11644             return(TNG_SUCCESS);
11645         }
11646     }
11647
11648     /* Take medium steps backward until a medium step backward would be too long
11649      * or the right frame set is found */
11650     while(file_pos > 0 && first_frame - medium_stride_length *
11651           n_frames_per_frame_set >= frame)
11652     {
11653         file_pos = frame_set->medium_stride_prev_frame_set_file_pos;
11654         if(file_pos > 0)
11655         {
11656             fseek(tng_data->input_file,
11657                   (long)file_pos,
11658                   SEEK_SET);
11659             /* Read block headers first to see what block is found. */
11660             stat = tng_block_header_read(tng_data, block);
11661             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11662             {
11663                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11664                        file_pos, __FILE__, __LINE__);
11665                 tng_block_destroy(&block);
11666                 return(TNG_CRITICAL);
11667             }
11668
11669             if(tng_block_read_next(tng_data, block,
11670                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11671             {
11672                 tng_block_destroy(&block);
11673                 return(TNG_CRITICAL);
11674             }
11675         }
11676         first_frame = tng_max_i64(frame_set->first_frame, 0);
11677         last_frame = first_frame + frame_set->n_frames - 1;
11678         if(frame >= first_frame && frame <= last_frame)
11679         {
11680             tng_block_destroy(&block);
11681             return(TNG_SUCCESS);
11682         }
11683     }
11684
11685     /* Take one step backward until the right frame set is found */
11686     while(file_pos > 0 && first_frame > frame && last_frame > frame)
11687     {
11688         file_pos = frame_set->prev_frame_set_file_pos;
11689         if(file_pos > 0)
11690         {
11691             fseek(tng_data->input_file,
11692                   (long)file_pos,
11693                   SEEK_SET);
11694             /* Read block headers first to see what block is found. */
11695             stat = tng_block_header_read(tng_data, block);
11696             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11697             {
11698                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11699                        file_pos, __FILE__, __LINE__);
11700                 tng_block_destroy(&block);
11701                 return(TNG_CRITICAL);
11702             }
11703
11704             if(tng_block_read_next(tng_data, block,
11705                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11706             {
11707                 tng_block_destroy(&block);
11708                 return(TNG_CRITICAL);
11709             }
11710         }
11711         first_frame = tng_max_i64(frame_set->first_frame, 0);
11712         last_frame = first_frame + frame_set->n_frames - 1;
11713         if(frame >= first_frame && frame <= last_frame)
11714         {
11715             tng_block_destroy(&block);
11716             return(TNG_SUCCESS);
11717         }
11718     }
11719
11720     /* If for some reason the current frame set is not yet found,
11721      * take one step forward until the right frame set is found */
11722     while(file_pos > 0 && first_frame < frame && last_frame < frame)
11723     {
11724         file_pos = frame_set->next_frame_set_file_pos;
11725         if(file_pos > 0)
11726         {
11727             fseek(tng_data->input_file,
11728                   (long)file_pos,
11729                   SEEK_SET);
11730             /* Read block headers first to see what block is found. */
11731             stat = tng_block_header_read(tng_data, block);
11732             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11733             {
11734                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11735                        file_pos, __FILE__, __LINE__);
11736                 tng_block_destroy(&block);
11737                 return(TNG_CRITICAL);
11738             }
11739
11740             if(tng_block_read_next(tng_data, block,
11741                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11742             {
11743                 tng_block_destroy(&block);
11744                 return(TNG_CRITICAL);
11745             }
11746         }
11747         first_frame = tng_max_i64(frame_set->first_frame, 0);
11748         last_frame = first_frame + frame_set->n_frames - 1;
11749         if(frame >= first_frame && frame <= last_frame)
11750         {
11751             tng_block_destroy(&block);
11752             return(TNG_SUCCESS);
11753         }
11754     }
11755
11756     tng_block_destroy(&block);
11757     return(TNG_FAILURE);
11758 }
11759
11760 tng_function_status DECLSPECDLLEXPORT tng_frame_set_next_frame_set_file_pos_get
11761                 (const tng_trajectory_t tng_data,
11762                  const tng_trajectory_frame_set_t frame_set,
11763                  int64_t *pos)
11764 {
11765     (void)tng_data;
11766
11767     TNG_ASSERT(frame_set, "TNG library: frame_set not initialised before accessing data.");
11768     TNG_ASSERT(pos, "TNG library: pos must not be a NULL pointer");
11769
11770     *pos = frame_set->next_frame_set_file_pos;
11771
11772     return(TNG_SUCCESS);
11773 }
11774
11775 tng_function_status DECLSPECDLLEXPORT tng_frame_set_prev_frame_set_file_pos_get
11776                 (const tng_trajectory_t tng_data,
11777                  const tng_trajectory_frame_set_t frame_set,
11778                  int64_t *pos)
11779 {
11780     (void)tng_data;
11781
11782     TNG_ASSERT(frame_set, "TNG library: frame_set not initialised before accessing data.");
11783     TNG_ASSERT(pos, "TNG library: pos must not be a NULL pointer");
11784
11785     *pos = frame_set->prev_frame_set_file_pos;
11786
11787     return(TNG_SUCCESS);
11788 }
11789
11790 tng_function_status DECLSPECDLLEXPORT tng_frame_set_frame_range_get
11791                 (const tng_trajectory_t tng_data,
11792                  const tng_trajectory_frame_set_t frame_set,
11793                  int64_t *first_frame,
11794                  int64_t *last_frame)
11795 {
11796     (void)tng_data;
11797
11798     TNG_ASSERT(first_frame, "TNG library: first_frame must not be a NULL pointer");
11799     TNG_ASSERT(last_frame, "TNG library: last_frame must not be a NULL pointer");
11800     TNG_ASSERT(frame_set, "TNG library: frame_set must not be a NULL pointer");
11801
11802     *first_frame = frame_set->first_frame;
11803     *last_frame = *first_frame + frame_set->n_frames - 1;
11804
11805     return(TNG_SUCCESS);
11806 }
11807
11808 /** Translate from the particle numbering used in a frame set to the real
11809  *  particle numbering - used in the molecule description.
11810  * @param frame_set is the frame_set containing the mappings to use.
11811  * @param local is the index number of the atom in this frame set
11812  * @param real is set to the index of the atom in the molecular system.
11813  * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the mapping
11814  * cannot be found.
11815  */
11816 static TNG_INLINE tng_function_status tng_particle_mapping_get_real_particle
11817                 (const tng_trajectory_frame_set_t frame_set,
11818                  const int64_t local,
11819                  int64_t *real)
11820 {
11821     int64_t i, n_blocks = frame_set->n_mapping_blocks, first;
11822     tng_particle_mapping_t mapping;
11823     if(n_blocks <= 0)
11824     {
11825         *real = local;
11826         return(TNG_SUCCESS);
11827     }
11828     for(i = 0; i < n_blocks; i++)
11829     {
11830         mapping = &frame_set->mappings[i];
11831         first = mapping->num_first_particle;
11832         if(local < first ||
11833            local >= first + mapping->n_particles)
11834         {
11835             continue;
11836         }
11837         *real = mapping->real_particle_numbers[local-first];
11838         return(TNG_SUCCESS);
11839     }
11840     *real = local;
11841     return(TNG_FAILURE);
11842 }
11843
11844 /** Translate from the real particle numbering to the particle numbering
11845  *  used in a frame set.
11846  * @param frame_set is the frame_set containing the mappings to use.
11847  * @param real is the index number of the atom in the molecular system.
11848  * @param local is set to the index of the atom in this frame set.
11849  * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the mapping
11850  * cannot be found.
11851  */
11852 /*static TNG_INLINE tng_function_status tng_particle_mapping_get_local_particle
11853                 (const tng_trajectory_frame_set_t frame_set,
11854                  const int64_t real,
11855                  int64_t *local)
11856 {
11857     int64_t i, j, n_blocks = frame_set->n_mapping_blocks;
11858     tng_particle_mapping_t mapping;
11859     if(n_blocks <= 0)
11860     {
11861         *local = real;
11862         return(TNG_SUCCESS);
11863     }
11864     for(i = 0; i < n_blocks; i++)
11865     {
11866         mapping = &frame_set->mappings[i];
11867         for(j = mapping->n_particles; j--;)
11868         {
11869             if(mapping->real_particle_numbers[j] == real)
11870             {
11871                 *local = j;
11872                 return(TNG_SUCCESS);
11873             }
11874         }
11875     }
11876     return(TNG_FAILURE);
11877 }
11878 */
11879
11880 tng_function_status DECLSPECDLLEXPORT tng_file_headers_read
11881                 (tng_trajectory_t tng_data,
11882                  const char hash_mode)
11883 {
11884     int cnt = 0, prev_pos = 0;
11885     tng_gen_block_t block;
11886
11887     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11888
11889     tng_data->n_trajectory_frame_sets = 0;
11890
11891     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
11892     {
11893         return(TNG_CRITICAL);
11894     }
11895
11896     if(!tng_data->input_file_len)
11897     {
11898         fseek(tng_data->input_file, 0, SEEK_END);
11899         tng_data->input_file_len = ftell(tng_data->input_file);
11900         fseek(tng_data->input_file, 0, SEEK_SET);
11901     }
11902
11903     tng_block_init(&block);
11904     /* Non trajectory blocks (they come before the trajectory
11905      * blocks in the file) */
11906     while (prev_pos < tng_data->input_file_len &&
11907            tng_block_header_read(tng_data, block) != TNG_CRITICAL &&
11908            block->id != -1 &&
11909            block->id != TNG_TRAJECTORY_FRAME_SET)
11910     {
11911         if(tng_block_read_next(tng_data, block,
11912                                hash_mode) == TNG_SUCCESS)
11913         {
11914             cnt++;
11915         }
11916         prev_pos = ftell(tng_data->input_file);
11917     }
11918
11919     /* Go back if a trajectory block was encountered */
11920     if(block->id == TNG_TRAJECTORY_FRAME_SET)
11921     {
11922         fseek(tng_data->input_file, prev_pos, SEEK_SET);
11923     }
11924
11925     tng_block_destroy(&block);
11926
11927     return(TNG_SUCCESS);
11928 }
11929
11930 tng_function_status DECLSPECDLLEXPORT tng_file_headers_write
11931                 (tng_trajectory_t tng_data,
11932                  const char hash_mode)
11933 {
11934     int i;
11935     tng_gen_block_t data_block;
11936
11937     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11938
11939     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
11940     {
11941         return(TNG_CRITICAL);
11942     }
11943
11944     /* TODO: If there is already frame set data written to this file (e.g. when
11945      * appending to an already existing file we might need to move frame sets to
11946      * the end of the file. */
11947
11948     if(tng_general_info_block_write(tng_data, hash_mode)
11949        != TNG_SUCCESS)
11950     {
11951         fprintf(stderr, "TNG library: Error writing general info block of file %s. %s: %d\n",
11952                 tng_data->input_file_path, __FILE__, __LINE__);
11953         return(TNG_CRITICAL);
11954     }
11955
11956     if(tng_molecules_block_write(tng_data, hash_mode)
11957         != TNG_SUCCESS)
11958     {
11959         fprintf(stderr, "TNG library: Error writing atom names block of file %s. %s: %d\n",
11960                 tng_data->input_file_path, __FILE__, __LINE__);
11961         return(TNG_CRITICAL);
11962     }
11963
11964     /* FIXME: Currently writing non-trajectory data blocks here.
11965      * Should perhaps be moved. */
11966     tng_block_init(&data_block);
11967     for(i = 0; i < tng_data->n_data_blocks; i++)
11968     {
11969         data_block->id = tng_data->non_tr_data[i].block_id;
11970         tng_data_block_write(tng_data, data_block,
11971                              i, hash_mode);
11972     }
11973
11974     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
11975     {
11976         data_block->id = tng_data->non_tr_particle_data[i].block_id;
11977         tng_particle_data_block_write(tng_data, data_block,
11978                                       i, 0, hash_mode);
11979     }
11980
11981     tng_block_destroy(&data_block);
11982
11983     return(TNG_SUCCESS);
11984 }
11985
11986 tng_function_status DECLSPECDLLEXPORT tng_block_read_next(tng_trajectory_t tng_data,
11987                                         tng_gen_block_t block,
11988                                         const char hash_mode)
11989 {
11990     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11991     TNG_ASSERT(block, "TNG library: block must be initialised and must not be a NULL pointer.");
11992
11993     switch(block->id)
11994     {
11995     case TNG_TRAJECTORY_FRAME_SET:
11996         return(tng_frame_set_block_read(tng_data, block, hash_mode));
11997     case TNG_PARTICLE_MAPPING:
11998         return(tng_trajectory_mapping_block_read(tng_data, block, hash_mode));
11999     case TNG_GENERAL_INFO:
12000         return(tng_general_info_block_read(tng_data, block, hash_mode));
12001     case TNG_MOLECULES:
12002         return(tng_molecules_block_read(tng_data, block, hash_mode));
12003     default:
12004         if(block->id >= TNG_TRAJ_BOX_SHAPE)
12005         {
12006             return(tng_data_block_contents_read(tng_data, block, hash_mode));
12007         }
12008         else
12009         {
12010             /* Skip to the next block */
12011             fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
12012             return(TNG_FAILURE);
12013         }
12014     }
12015 }
12016
12017 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read
12018                 (tng_trajectory_t tng_data,
12019                  const char hash_mode)
12020 {
12021     long file_pos;
12022     tng_gen_block_t block;
12023     tng_function_status stat;
12024
12025     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12026
12027     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12028     {
12029         return(TNG_CRITICAL);
12030     }
12031
12032     file_pos = ftell(tng_data->input_file);
12033
12034     tng_block_init(&block);
12035
12036     if(!tng_data->input_file_len)
12037     {
12038         fseek(tng_data->input_file, 0, SEEK_END);
12039         tng_data->input_file_len = ftell(tng_data->input_file);
12040         fseek(tng_data->input_file, file_pos, SEEK_SET);
12041     }
12042
12043     /* Read block headers first to see what block is found. */
12044     stat = tng_block_header_read(tng_data, block);
12045     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12046     {
12047         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
12048                file_pos, __FILE__, __LINE__);
12049         tng_block_destroy(&block);
12050         return(TNG_CRITICAL);
12051     }
12052
12053     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
12054
12055     if(tng_block_read_next(tng_data, block,
12056                            hash_mode) == TNG_SUCCESS)
12057     {
12058         tng_data->n_trajectory_frame_sets++;
12059         file_pos = ftell(tng_data->input_file);
12060         /* Read all blocks until next frame set block */
12061         stat = tng_block_header_read(tng_data, block);
12062         while(file_pos < tng_data->input_file_len &&
12063               stat != TNG_CRITICAL &&
12064               block->id != TNG_TRAJECTORY_FRAME_SET)
12065         {
12066             stat = tng_block_read_next(tng_data, block,
12067                                        hash_mode);
12068             if(stat != TNG_CRITICAL)
12069             {
12070                 file_pos = ftell(tng_data->input_file);
12071                 if(file_pos < tng_data->input_file_len)
12072                 {
12073                     stat = tng_block_header_read(tng_data, block);
12074                 }
12075             }
12076         }
12077         if(stat == TNG_CRITICAL)
12078         {
12079             fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
12080                    file_pos, __FILE__, __LINE__);
12081             tng_block_destroy(&block);
12082             return(stat);
12083         }
12084
12085         if(block->id == TNG_TRAJECTORY_FRAME_SET)
12086         {
12087             fseek(tng_data->input_file, file_pos, SEEK_SET);
12088         }
12089     }
12090
12091     tng_block_destroy(&block);
12092
12093     return(TNG_SUCCESS);
12094 }
12095
12096
12097 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_current_only_data_from_block_id
12098                 (tng_trajectory_t tng_data,
12099                  const char hash_mode,
12100                  const int64_t block_id)
12101 {
12102     long file_pos;
12103     tng_gen_block_t block;
12104     tng_function_status stat;
12105     int found_flag = 1;
12106
12107     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12108
12109     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12110     {
12111         return(TNG_CRITICAL);
12112     }
12113
12114     file_pos = (long)tng_data->current_trajectory_frame_set_input_file_pos;
12115
12116     if(file_pos < 0)
12117     {
12118         /* No current frame set. This means that the first frame set must be
12119          * read */
12120         found_flag = 0;
12121         file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
12122     }
12123
12124     if(file_pos > 0)
12125     {
12126         fseek(tng_data->input_file,
12127               file_pos,
12128               SEEK_SET);
12129     }
12130     else
12131     {
12132         return(TNG_FAILURE);
12133     }
12134
12135     tng_block_init(&block);
12136
12137     if(!tng_data->input_file_len)
12138     {
12139         fseek(tng_data->input_file, 0, SEEK_END);
12140         tng_data->input_file_len = ftell(tng_data->input_file);
12141         fseek(tng_data->input_file, file_pos, SEEK_SET);
12142     }
12143
12144     /* Read block headers first to see what block is found. */
12145     stat = tng_block_header_read(tng_data, block);
12146     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12147     {
12148         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
12149                file_pos, __FILE__, __LINE__);
12150         tng_block_destroy(&block);
12151         return(TNG_CRITICAL);
12152     }
12153     /* If the current frame set had already been read skip its block contents */
12154     if(found_flag)
12155     {
12156         fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
12157     }
12158     /* Otherwiese read the frame set block */
12159     else
12160     {
12161         stat = tng_block_read_next(tng_data, block,
12162                                    hash_mode);
12163         if(stat != TNG_SUCCESS)
12164         {
12165             fprintf(stderr, "TNG library: Cannot read frame set block. %s: %d\n", __FILE__, __LINE__);
12166             tng_block_destroy(&block);
12167             return(stat);
12168         }
12169     }
12170     file_pos = ftell(tng_data->input_file);
12171
12172     found_flag = 0;
12173
12174     /* Read only blocks of the requested ID
12175         * until next frame set block */
12176     stat = tng_block_header_read(tng_data, block);
12177     while(file_pos < tng_data->input_file_len &&
12178             stat != TNG_CRITICAL &&
12179             block->id != TNG_TRAJECTORY_FRAME_SET)
12180     {
12181         if(block->id == block_id)
12182         {
12183             stat = tng_block_read_next(tng_data, block,
12184                                        hash_mode);
12185             if(stat != TNG_CRITICAL)
12186             {
12187                 file_pos = ftell(tng_data->input_file);
12188                 found_flag = 1;
12189                 if(file_pos < tng_data->input_file_len)
12190                 {
12191                     stat = tng_block_header_read(tng_data, block);
12192                 }
12193             }
12194         }
12195         else
12196         {
12197             file_pos += (long)(block->block_contents_size + block->header_contents_size);
12198             fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
12199             if(file_pos < tng_data->input_file_len)
12200             {
12201                 stat = tng_block_header_read(tng_data, block);
12202             }
12203         }
12204     }
12205     if(stat == TNG_CRITICAL)
12206     {
12207         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
12208                 file_pos, __FILE__, __LINE__);
12209         tng_block_destroy(&block);
12210         return(stat);
12211     }
12212
12213     if(block->id == TNG_TRAJECTORY_FRAME_SET)
12214     {
12215         fseek(tng_data->input_file, file_pos, SEEK_SET);
12216     }
12217
12218     tng_block_destroy(&block);
12219
12220     if(found_flag)
12221     {
12222         return(TNG_SUCCESS);
12223     }
12224     else
12225     {
12226         return(TNG_FAILURE);
12227     }
12228 }
12229
12230 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next
12231                 (tng_trajectory_t tng_data,
12232                  const char hash_mode)
12233 {
12234     long file_pos;
12235
12236     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12237
12238     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12239     {
12240         return(TNG_CRITICAL);
12241     }
12242
12243     file_pos = (long)tng_data->current_trajectory_frame_set.next_frame_set_file_pos;
12244
12245     if(file_pos < 0 && tng_data->current_trajectory_frame_set_input_file_pos <= 0)
12246     {
12247         file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
12248     }
12249
12250     if(file_pos > 0)
12251     {
12252         fseek(tng_data->input_file,
12253               file_pos,
12254               SEEK_SET);
12255     }
12256     else
12257     {
12258         return(TNG_FAILURE);
12259     }
12260
12261     return(tng_frame_set_read(tng_data, hash_mode));
12262 }
12263
12264 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next_only_data_from_block_id
12265                 (tng_trajectory_t tng_data,
12266                  const char hash_mode,
12267                  const int64_t block_id)
12268 {
12269     long file_pos;
12270     tng_gen_block_t block;
12271     tng_function_status stat;
12272
12273     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12274
12275     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12276     {
12277         return(TNG_CRITICAL);
12278     }
12279
12280     file_pos = (long)tng_data->current_trajectory_frame_set.next_frame_set_file_pos;
12281
12282     if(file_pos < 0 && tng_data->current_trajectory_frame_set_input_file_pos <= 0)
12283     {
12284         file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
12285     }
12286
12287     if(file_pos > 0)
12288     {
12289         fseek(tng_data->input_file,
12290               file_pos,
12291               SEEK_SET);
12292     }
12293     else
12294     {
12295         return(TNG_FAILURE);
12296     }
12297
12298     tng_block_init(&block);
12299
12300     if(!tng_data->input_file_len)
12301     {
12302         fseek(tng_data->input_file, 0, SEEK_END);
12303         tng_data->input_file_len = ftell(tng_data->input_file);
12304         fseek(tng_data->input_file, file_pos, SEEK_SET);
12305     }
12306
12307     /* Read block headers first to see what block is found. */
12308     stat = tng_block_header_read(tng_data, block);
12309     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12310     {
12311         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
12312                file_pos, __FILE__, __LINE__);
12313         tng_block_destroy(&block);
12314         return(TNG_CRITICAL);
12315     }
12316
12317     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
12318
12319     if(tng_block_read_next(tng_data, block,
12320                            hash_mode) == TNG_SUCCESS)
12321     {
12322         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, hash_mode, block_id);
12323     }
12324
12325     tng_block_destroy(&block);
12326
12327     return(stat);
12328 }
12329
12330 tng_function_status tng_frame_set_write(tng_trajectory_t tng_data,
12331                                         const char hash_mode)
12332 {
12333     int i, j;
12334     tng_gen_block_t block;
12335     tng_trajectory_frame_set_t frame_set;
12336     tng_function_status stat;
12337
12338     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12339
12340     frame_set = &tng_data->current_trajectory_frame_set;
12341
12342     if(frame_set->n_written_frames == frame_set->n_frames)
12343     {
12344         return(TNG_SUCCESS);
12345     }
12346
12347     tng_data->current_trajectory_frame_set_output_file_pos =
12348     ftell(tng_data->output_file);
12349     tng_data->last_trajectory_frame_set_output_file_pos =
12350     tng_data->current_trajectory_frame_set_output_file_pos;
12351
12352     if(tng_data->current_trajectory_frame_set_output_file_pos <= 0)
12353     {
12354         return(TNG_FAILURE);
12355     }
12356
12357     if(tng_data->first_trajectory_frame_set_output_file_pos == -1)
12358     {
12359         tng_data->first_trajectory_frame_set_output_file_pos =
12360         tng_data->current_trajectory_frame_set_output_file_pos;
12361     }
12362
12363     tng_block_init(&block);
12364
12365     if(tng_frame_set_block_write(tng_data, block, hash_mode) != TNG_SUCCESS)
12366     {
12367         tng_block_destroy(&block);
12368         return(TNG_FAILURE);
12369     }
12370
12371     /* Write non-particle data blocks */
12372     for(i = 0; i<frame_set->n_data_blocks; i++)
12373     {
12374         block->id = frame_set->tr_data[i].block_id;
12375         tng_data_block_write(tng_data, block, i, hash_mode);
12376     }
12377     /* Write the mapping blocks and particle data blocks*/
12378     if(frame_set->n_mapping_blocks)
12379     {
12380         for(i = 0; i < frame_set->n_mapping_blocks; i++)
12381         {
12382             block->id = TNG_PARTICLE_MAPPING;
12383             if(frame_set->mappings[i].n_particles > 0)
12384             {
12385                 tng_trajectory_mapping_block_write(tng_data, block, i, hash_mode);
12386                 for(j = 0; j<frame_set->n_particle_data_blocks; j++)
12387                 {
12388                     block->id = frame_set->tr_particle_data[j].block_id;
12389                     tng_particle_data_block_write(tng_data, block,
12390                                                   j, &frame_set->mappings[i],
12391                                                   hash_mode);
12392                 }
12393             }
12394         }
12395     }
12396     else
12397     {
12398         for(i = 0; i<frame_set->n_particle_data_blocks; i++)
12399         {
12400             block->id = frame_set->tr_particle_data[i].block_id;
12401             tng_particle_data_block_write(tng_data, block,
12402                                           i, 0, hash_mode);
12403         }
12404     }
12405
12406
12407     /* Update pointers in the general info block */
12408     stat = tng_header_pointers_update(tng_data, hash_mode);
12409
12410     if(stat == TNG_SUCCESS)
12411     {
12412         stat = tng_frame_set_pointers_update(tng_data, hash_mode);
12413     }
12414
12415     tng_block_destroy(&block);
12416
12417     frame_set->n_unwritten_frames = 0;
12418
12419     fflush(tng_data->output_file);
12420
12421     return(stat);
12422 }
12423
12424 tng_function_status DECLSPECDLLEXPORT tng_frame_set_premature_write
12425                 (tng_trajectory_t tng_data,
12426                  const char hash_mode)
12427 {
12428     tng_trajectory_frame_set_t frame_set;
12429
12430     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12431
12432     frame_set = &tng_data->current_trajectory_frame_set;
12433
12434     if(frame_set->n_unwritten_frames == 0)
12435     {
12436         return(TNG_SUCCESS);
12437     }
12438     frame_set->n_frames = frame_set->n_unwritten_frames;
12439
12440     return(tng_frame_set_write(tng_data, hash_mode));
12441 }
12442
12443 tng_function_status DECLSPECDLLEXPORT tng_frame_set_new
12444                 (tng_trajectory_t tng_data,
12445                  const int64_t first_frame,
12446                  const int64_t n_frames)
12447 {
12448     tng_gen_block_t block;
12449     tng_trajectory_frame_set_t frame_set;
12450     FILE *temp = tng_data->input_file;
12451     int64_t curr_pos;
12452
12453     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12454     TNG_ASSERT(first_frame >= 0, "TNG library: first_frame must be >= 0.");
12455     TNG_ASSERT(n_frames >= 0, "TNG library: n_frames must be >= 0.");
12456
12457     frame_set = &tng_data->current_trajectory_frame_set;
12458
12459     curr_pos = ftell(tng_data->output_file);
12460
12461     if(curr_pos <= 10)
12462     {
12463         tng_file_headers_write(tng_data, TNG_USE_HASH);
12464     }
12465
12466     /* Set pointer to previous frame set to the one that was loaded
12467      * before.
12468      * FIXME: This is a bit risky. If they are not added in order
12469      * it will be wrong. */
12470     if(tng_data->n_trajectory_frame_sets)
12471     {
12472         frame_set->prev_frame_set_file_pos =
12473         tng_data->current_trajectory_frame_set_output_file_pos;
12474     }
12475
12476     tng_data->current_trajectory_frame_set_output_file_pos =
12477     ftell(tng_data->output_file);
12478
12479     tng_data->n_trajectory_frame_sets++;
12480
12481     /* Set the medium range pointers */
12482     if(tng_data->n_trajectory_frame_sets == tng_data->medium_stride_length + 1)
12483     {
12484         frame_set->medium_stride_prev_frame_set_file_pos =
12485         tng_data->first_trajectory_frame_set_output_file_pos;
12486     }
12487     else if(tng_data->n_trajectory_frame_sets > tng_data->medium_stride_length + 1)
12488     {
12489         /* FIXME: Currently only working if the previous frame set has its
12490          * medium stride pointer already set. This might need some fixing. */
12491         if(frame_set->medium_stride_prev_frame_set_file_pos != -1 &&
12492            frame_set->medium_stride_prev_frame_set_file_pos != 0)
12493         {
12494             tng_block_init(&block);
12495             tng_data->input_file = tng_data->output_file;
12496
12497             curr_pos = ftell(tng_data->output_file);
12498             fseek(tng_data->output_file,
12499                   (long)frame_set->medium_stride_prev_frame_set_file_pos,
12500                   SEEK_SET);
12501
12502             if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
12503             {
12504                 fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
12505                     __FILE__, __LINE__);
12506                 tng_data->input_file = temp;
12507                 tng_block_destroy(&block);
12508                 return(TNG_CRITICAL);
12509             }
12510
12511             /* Read the next frame set from the previous frame set and one
12512              * medium stride step back */
12513             fseek(tng_data->output_file, (long)block->block_contents_size - 6 *
12514                 sizeof(int64_t), SEEK_CUR);
12515             if(fread(&frame_set->medium_stride_prev_frame_set_file_pos,
12516                sizeof(frame_set->medium_stride_prev_frame_set_file_pos),
12517                1, tng_data->output_file) == 0)
12518             {
12519                 fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
12520                 tng_data->input_file = temp;
12521                 tng_block_destroy(&block);
12522                 return(TNG_CRITICAL);
12523             }
12524
12525             if(tng_data->input_endianness_swap_func_64)
12526             {
12527                 if(tng_data->input_endianness_swap_func_64(tng_data,
12528                    &frame_set->medium_stride_prev_frame_set_file_pos)
12529                     != TNG_SUCCESS)
12530                 {
12531                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
12532                             __FILE__, __LINE__);
12533                 }
12534             }
12535
12536             tng_block_destroy(&block);
12537
12538             /* Set the long range pointers */
12539             if(tng_data->n_trajectory_frame_sets == tng_data->long_stride_length + 1)
12540             {
12541                 frame_set->long_stride_prev_frame_set_file_pos =
12542                 tng_data->first_trajectory_frame_set_output_file_pos;
12543             }
12544             else if(tng_data->n_trajectory_frame_sets > tng_data->medium_stride_length + 1)
12545             {
12546                 /* FIXME: Currently only working if the previous frame set has its
12547                 * long stride pointer already set. This might need some fixing. */
12548                 if(frame_set->long_stride_prev_frame_set_file_pos != -1 &&
12549                 frame_set->long_stride_prev_frame_set_file_pos != 0)
12550                 {
12551                     tng_block_init(&block);
12552                     tng_data->input_file = tng_data->output_file;
12553
12554                     fseek(tng_data->output_file,
12555                           (long)frame_set->long_stride_prev_frame_set_file_pos,
12556                           SEEK_SET);
12557
12558                     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
12559                     {
12560                         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
12561                             __FILE__, __LINE__);
12562                         tng_data->input_file = temp;
12563                         tng_block_destroy(&block);
12564                         return(TNG_CRITICAL);
12565                     }
12566
12567                     /* Read the next frame set from the previous frame set and one
12568                     * long stride step back */
12569                     fseek(tng_data->output_file, (long)block->block_contents_size - 6 *
12570                           sizeof(int64_t), SEEK_CUR);
12571
12572                     tng_block_destroy(&block);
12573
12574                     if(fread(&frame_set->long_stride_prev_frame_set_file_pos,
12575                     sizeof(frame_set->long_stride_prev_frame_set_file_pos),
12576                     1, tng_data->output_file) == 0)
12577                     {
12578                         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
12579                         tng_data->input_file = temp;
12580                         return(TNG_CRITICAL);
12581                     }
12582
12583                     if(tng_data->input_endianness_swap_func_64)
12584                     {
12585                         if(tng_data->input_endianness_swap_func_64(tng_data,
12586                            &frame_set->long_stride_prev_frame_set_file_pos)
12587                             != TNG_SUCCESS)
12588                         {
12589                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
12590                                     __FILE__, __LINE__);
12591                         }
12592                     }
12593
12594                 }
12595             }
12596
12597             tng_data->input_file = temp;
12598             fseek(tng_data->output_file, (long)curr_pos, SEEK_SET);
12599         }
12600     }
12601
12602     frame_set->first_frame = first_frame;
12603     frame_set->n_frames = n_frames;
12604     frame_set->n_written_frames = 0;
12605     frame_set->n_unwritten_frames = 0;
12606     frame_set->first_frame_time = -1;
12607
12608     if(tng_data->first_trajectory_frame_set_output_file_pos == -1 ||
12609        tng_data->first_trajectory_frame_set_output_file_pos == 0)
12610     {
12611         tng_data->first_trajectory_frame_set_output_file_pos =
12612         tng_data->current_trajectory_frame_set_output_file_pos;
12613     }
12614     /* FIXME: Should check the frame number instead of the file_pos,
12615      * in case frame sets are not in order */
12616     if(tng_data->last_trajectory_frame_set_output_file_pos == -1 ||
12617        tng_data->last_trajectory_frame_set_output_file_pos == 0 ||
12618        tng_data->last_trajectory_frame_set_output_file_pos <
12619        tng_data->current_trajectory_frame_set_output_file_pos)
12620     {
12621         tng_data->last_trajectory_frame_set_output_file_pos =
12622         tng_data->current_trajectory_frame_set_output_file_pos;
12623     }
12624
12625     return(TNG_SUCCESS);
12626 }
12627
12628 tng_function_status DECLSPECDLLEXPORT tng_frame_set_with_time_new
12629                 (tng_trajectory_t tng_data,
12630                  const int64_t first_frame,
12631                  const int64_t n_frames,
12632                  const double first_frame_time)
12633 {
12634     tng_function_status stat;
12635
12636     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12637     TNG_ASSERT(first_frame >= 0, "TNG library: first_frame must be >= 0.");
12638     TNG_ASSERT(n_frames >= 0, "TNG library: n_frames must be >= 0.");
12639     TNG_ASSERT(first_frame_time >= 0, "TNG library: first_frame_time must be >= 0.");
12640
12641
12642     stat = tng_frame_set_new(tng_data, first_frame, n_frames);
12643     if(stat != TNG_SUCCESS)
12644     {
12645         return(stat);
12646     }
12647     stat = tng_frame_set_first_frame_time_set(tng_data, first_frame_time);
12648
12649     return(stat);
12650 }
12651
12652 tng_function_status DECLSPECDLLEXPORT tng_frame_set_first_frame_time_set
12653                 (tng_trajectory_t tng_data,
12654                  const double first_frame_time)
12655 {
12656     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12657     TNG_ASSERT(first_frame_time >= 0, "TNG library: first_frame_time must be >= 0.");
12658
12659     tng_data->current_trajectory_frame_set.first_frame_time = first_frame_time;
12660
12661     return(TNG_SUCCESS);
12662 }
12663
12664 tng_function_status DECLSPECDLLEXPORT tng_first_frame_nr_of_next_frame_set_get
12665                 (const tng_trajectory_t tng_data,
12666                  int64_t *frame)
12667 {
12668     long file_pos, next_frame_set_file_pos;
12669     tng_gen_block_t block;
12670     tng_function_status stat;
12671
12672     tng_trajectory_frame_set_t frame_set;
12673
12674     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12675     TNG_ASSERT(tng_data->input_file, "TNG library: An input file must be open to find the next frame set");
12676     TNG_ASSERT(frame, "TNG library: frame must not be a NULL pointer");
12677
12678     file_pos = ftell(tng_data->input_file);
12679
12680     if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
12681     {
12682         next_frame_set_file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
12683     }
12684     else
12685     {
12686         frame_set = &tng_data->current_trajectory_frame_set;
12687         next_frame_set_file_pos = (long)frame_set->next_frame_set_file_pos;
12688     }
12689
12690     if(next_frame_set_file_pos <= 0)
12691     {
12692         return(TNG_FAILURE);
12693     }
12694
12695     fseek(tng_data->input_file, (long)next_frame_set_file_pos, SEEK_SET);
12696     /* Read block headers first to see that a frame set block is found. */
12697     tng_block_init(&block);
12698     stat = tng_block_header_read(tng_data, block);
12699     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12700     {
12701         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
12702                file_pos, __FILE__, __LINE__);
12703         return(TNG_CRITICAL);
12704     }
12705 /*    if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
12706     {
12707         tng_block_read_next(tng_data, block, TNG_USE_HASH);
12708     }*/
12709     tng_block_destroy(&block);
12710
12711     if(fread(frame, sizeof(int64_t), 1, tng_data->input_file) == 0)
12712     {
12713         fprintf(stderr, "TNG library: Cannot read first frame of next frame set. %s: %d\n",
12714                __FILE__, __LINE__);
12715         return(TNG_CRITICAL);
12716     }
12717     fseek(tng_data->input_file, file_pos, SEEK_SET);
12718
12719     return(TNG_SUCCESS);
12720 }
12721
12722 tng_function_status DECLSPECDLLEXPORT tng_data_block_add
12723                 (tng_trajectory_t tng_data,
12724                  const int64_t id,
12725                  const char *block_name,
12726                  const char datatype,
12727                  const char block_type_flag,
12728                  int64_t n_frames,
12729                  const int64_t n_values_per_frame,
12730                  int64_t stride_length,
12731                  const int64_t codec_id,
12732                  void *new_data)
12733 {
12734     int i, j, size, len;
12735     tng_trajectory_frame_set_t frame_set;
12736     tng_non_particle_data_t data;
12737     char **first_dim_values;
12738     char *new_data_c=new_data;
12739     int64_t n_frames_div;
12740
12741     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12742     TNG_ASSERT(block_name, "TNG library: block_name must not be a NULL pointer.");
12743     TNG_ASSERT(n_values_per_frame > 0, "TNG library: n_values_per_frame must be a positive integer.");
12744
12745     frame_set = &tng_data->current_trajectory_frame_set;
12746
12747     if(stride_length <= 0)
12748     {
12749         stride_length = 1;
12750     }
12751
12752     /* If the block does not exist, create it */
12753     if(tng_data_find(tng_data, id, &data) != TNG_SUCCESS)
12754     {
12755         if(tng_data_block_create(tng_data, block_type_flag) !=
12756             TNG_SUCCESS)
12757         {
12758             fprintf(stderr, "TNG library: Cannot create data block. %s: %d\n",
12759                    __FILE__, __LINE__);
12760             return(TNG_CRITICAL);
12761         }
12762         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
12763         {
12764             data = &frame_set->tr_data[frame_set->n_data_blocks - 1];
12765         }
12766         else
12767         {
12768             data = &tng_data->non_tr_data[tng_data->n_data_blocks - 1];
12769         }
12770         data->block_id = id;
12771
12772         data->block_name = malloc(strlen(block_name) + 1);
12773         if(!data->block_name)
12774         {
12775             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
12776                    (int)strlen(block_name)+1, __FILE__, __LINE__);
12777             return(TNG_CRITICAL);
12778         }
12779         strncpy(data->block_name, block_name, strlen(block_name) + 1);
12780
12781         data->values = 0;
12782         /* FIXME: Memory leak from strings. */
12783         data->strings = 0;
12784         data->last_retrieved_frame = -1;
12785     }
12786
12787     data->datatype = datatype;
12788     data->stride_length = tng_max_i64(stride_length, 1);
12789     data->n_values_per_frame = n_values_per_frame;
12790     data->n_frames = n_frames;
12791     data->codec_id = codec_id;
12792     data->compression_multiplier = 1.0;
12793     /* FIXME: This can cause problems. */
12794     data->first_frame_with_data = frame_set->first_frame;
12795
12796     switch(datatype)
12797     {
12798     case TNG_FLOAT_DATA:
12799         size = sizeof(float);
12800         break;
12801     case TNG_INT_DATA:
12802         size = sizeof(int64_t);
12803         break;
12804     case TNG_DOUBLE_DATA:
12805     default:
12806         size = sizeof(double);
12807         break;
12808     }
12809
12810     if(new_data_c)
12811     {
12812         /* Allocate memory */
12813         if(tng_allocate_data_mem(tng_data, data, n_frames, stride_length,
12814                                  n_values_per_frame) !=
12815         TNG_SUCCESS)
12816         {
12817             fprintf(stderr, "TNG library: Cannot allocate data memory. %s: %d\n",
12818                 __FILE__, __LINE__);
12819             return(TNG_CRITICAL);
12820         }
12821
12822         if(n_frames > frame_set->n_unwritten_frames)
12823         {
12824             frame_set->n_unwritten_frames = n_frames;
12825         }
12826
12827         n_frames_div = (n_frames % stride_length) ?
12828                      n_frames / stride_length + 1:
12829                      n_frames / stride_length;
12830
12831         if(datatype == TNG_CHAR_DATA)
12832         {
12833             for(i = 0; i < n_frames_div; i++)
12834             {
12835                 first_dim_values = data->strings[i];
12836                 for(j = 0; j < n_values_per_frame; j++)
12837                 {
12838                     len = tng_min_i((int)strlen(new_data_c) + 1,
12839                                 TNG_MAX_STR_LEN);
12840                     if(first_dim_values[j])
12841                     {
12842                         free(first_dim_values[j]);
12843                     }
12844                     first_dim_values[j] = malloc(len);
12845                     if(!first_dim_values[j])
12846                     {
12847                         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
12848                             len, __FILE__, __LINE__);
12849                         return(TNG_CRITICAL);
12850                     }
12851                     strncpy(first_dim_values[j],
12852                             new_data_c, len);
12853                     new_data_c += len;
12854                 }
12855             }
12856         }
12857         else
12858         {
12859             memcpy(data->values, new_data, size * n_frames_div *
12860                    n_values_per_frame);
12861         }
12862     }
12863
12864     return(TNG_SUCCESS);
12865 }
12866
12867 tng_function_status DECLSPECDLLEXPORT tng_particle_data_block_add
12868                 (tng_trajectory_t tng_data,
12869                  const int64_t id,
12870                  const char *block_name,
12871                  const char datatype,
12872                  const char block_type_flag,
12873                  int64_t n_frames,
12874                  const int64_t n_values_per_frame,
12875                  int64_t stride_length,
12876                  const int64_t num_first_particle,
12877                  const int64_t n_particles,
12878                  const int64_t codec_id,
12879                  void *new_data)
12880 {
12881     int i, size, len;
12882     int64_t j, k;
12883     int64_t tot_n_particles, n_frames_div;
12884     char ***first_dim_values, **second_dim_values;
12885     tng_trajectory_frame_set_t frame_set;
12886     tng_particle_data_t data;
12887     char *new_data_c=new_data;
12888
12889     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12890     TNG_ASSERT(block_name, "TNG library: block_name mustnot be a NULL pointer.");
12891     TNG_ASSERT(n_values_per_frame > 0, "TNG library: n_values_per_frame must be a positive integer.");
12892     TNG_ASSERT(num_first_particle >= 0, "TNG library: num_first_particle must be >= 0.");
12893     TNG_ASSERT(n_particles >= 0, "TNG library: n_particles must be >= 0.");
12894
12895
12896     frame_set = &tng_data->current_trajectory_frame_set;
12897
12898     if(stride_length <= 0)
12899     {
12900         stride_length = 1;
12901     }
12902
12903     /* If the block does not exist, create it */
12904     if(tng_particle_data_find(tng_data, id, &data) != TNG_SUCCESS)
12905     {
12906         if(tng_particle_data_block_create(tng_data, block_type_flag) !=
12907             TNG_SUCCESS)
12908         {
12909             fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
12910                    __FILE__, __LINE__);
12911             return(TNG_CRITICAL);
12912         }
12913         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
12914         {
12915             data = &frame_set->tr_particle_data[frame_set->
12916                                                 n_particle_data_blocks - 1];
12917         }
12918         else
12919         {
12920             data = &tng_data->non_tr_particle_data[tng_data->
12921                                                    n_particle_data_blocks - 1];
12922         }
12923         data->block_id = id;
12924
12925         data->block_name = malloc(strlen(block_name) + 1);
12926         if(!data->block_name)
12927         {
12928             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
12929                    (int)strlen(block_name)+1, __FILE__, __LINE__);
12930             return(TNG_CRITICAL);
12931         }
12932         strncpy(data->block_name, block_name, strlen(block_name) + 1);
12933
12934         data->datatype = datatype;
12935
12936         data->values = 0;
12937         /* FIXME: Memory leak from strings. */
12938         data->strings = 0;
12939         data->last_retrieved_frame = -1;
12940     }
12941
12942     data->stride_length = tng_max_i64(stride_length, 1);
12943     data->n_values_per_frame = n_values_per_frame;
12944     data->n_frames = n_frames;
12945     data->codec_id = codec_id;
12946     data->compression_multiplier = 1.0;
12947     /* FIXME: This can cause problems. */
12948     data->first_frame_with_data = frame_set->first_frame;
12949
12950     if(block_type_flag == TNG_TRAJECTORY_BLOCK && tng_data->var_num_atoms_flag)
12951     {
12952         tot_n_particles = frame_set->n_particles;
12953     }
12954     else
12955     {
12956         tot_n_particles = tng_data->n_particles;
12957     }
12958
12959     /* If data values are supplied add that data to the data block. */
12960     if(new_data_c)
12961     {
12962         /* Allocate memory */
12963         if(tng_allocate_particle_data_mem(tng_data, data, n_frames,
12964                                           stride_length, tot_n_particles,
12965                                           n_values_per_frame) !=
12966         TNG_SUCCESS)
12967         {
12968             fprintf(stderr, "TNG library: Cannot allocate particle data memory. %s: %d\n",
12969                 __FILE__, __LINE__);
12970             return(TNG_CRITICAL);
12971         }
12972
12973         if(n_frames > frame_set->n_unwritten_frames)
12974         {
12975             frame_set->n_unwritten_frames = n_frames;
12976         }
12977
12978         n_frames_div = (n_frames % stride_length) ?
12979                      n_frames / stride_length + 1:
12980                      n_frames / stride_length;
12981
12982         if(datatype == TNG_CHAR_DATA)
12983         {
12984             for(i = 0; i < n_frames_div; i++)
12985             {
12986                 first_dim_values = data->strings[i];
12987                 for(j = num_first_particle; j < num_first_particle + n_particles;
12988                     j++)
12989                 {
12990                     second_dim_values = first_dim_values[j];
12991                     for(k = 0; k < n_values_per_frame; k++)
12992                     {
12993                         len = tng_min_i((int)strlen(new_data_c) + 1,
12994                                 TNG_MAX_STR_LEN);
12995                         if(second_dim_values[k])
12996                         {
12997                             free(second_dim_values[k]);
12998                         }
12999                         second_dim_values[k] = malloc(len);
13000                         if(!second_dim_values[k])
13001                         {
13002                             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
13003                                 len, __FILE__, __LINE__);
13004                             return(TNG_CRITICAL);
13005                         }
13006                         strncpy(second_dim_values[k],
13007                                 new_data_c, len);
13008                         new_data_c += len;
13009                     }
13010                 }
13011             }
13012         }
13013         else
13014         {
13015             switch(datatype)
13016             {
13017             case TNG_INT_DATA:
13018                 size = sizeof(int64_t);
13019                 break;
13020             case TNG_FLOAT_DATA:
13021                 size = sizeof(float);
13022                 break;
13023             case TNG_DOUBLE_DATA:
13024             default:
13025                 size = sizeof(double);
13026             }
13027
13028             memcpy(data->values, new_data, size * n_frames_div *
13029                    n_particles * n_values_per_frame);
13030         }
13031     }
13032
13033     return(TNG_SUCCESS);
13034 }
13035
13036 tng_function_status DECLSPECDLLEXPORT tng_data_block_name_get
13037                 (tng_trajectory_t tng_data,
13038                  int64_t block_id,
13039                  char *name,
13040                  int max_len)
13041 {
13042     int64_t i;
13043     tng_trajectory_frame_set_t frame_set;
13044     tng_function_status stat;
13045     tng_particle_data_t p_data;
13046     tng_non_particle_data_t np_data;
13047     int block_type = -1;
13048
13049     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13050     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
13051
13052     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
13053     {
13054         p_data = &tng_data->non_tr_particle_data[i];
13055         if(p_data->block_id == block_id)
13056         {
13057             strncpy(name, p_data->block_name, max_len);
13058             name[max_len - 1] = '\0';
13059             return(TNG_SUCCESS);
13060         }
13061     }
13062     for(i = 0; i < tng_data->n_data_blocks; i++)
13063     {
13064         np_data = &tng_data->non_tr_data[i];
13065         if(np_data->block_id == block_id)
13066         {
13067             strncpy(name, np_data->block_name, max_len);
13068             name[max_len - 1] = '\0';
13069             return(TNG_SUCCESS);
13070         }
13071     }
13072
13073     frame_set = &tng_data->current_trajectory_frame_set;
13074
13075     stat = tng_particle_data_find(tng_data, block_id, &p_data);
13076     if(stat == TNG_SUCCESS)
13077     {
13078         block_type = TNG_PARTICLE_BLOCK_DATA;
13079     }
13080     else
13081     {
13082         stat = tng_data_find(tng_data, block_id, &np_data);
13083         if(stat == TNG_SUCCESS)
13084         {
13085             block_type = TNG_NON_PARTICLE_BLOCK_DATA;
13086         }
13087         else
13088         {
13089             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
13090             if(stat != TNG_SUCCESS)
13091             {
13092                 return(stat);
13093             }
13094             stat = tng_particle_data_find(tng_data, block_id, &p_data);
13095             if(stat == TNG_SUCCESS)
13096             {
13097                 block_type = TNG_PARTICLE_BLOCK_DATA;
13098             }
13099             else
13100             {
13101                 stat = tng_data_find(tng_data, block_id, &np_data);
13102                 if(stat == TNG_SUCCESS)
13103                 {
13104                     block_type = TNG_NON_PARTICLE_BLOCK_DATA;
13105                 }
13106             }
13107         }
13108     }
13109     if(block_type == TNG_PARTICLE_BLOCK_DATA)
13110     {
13111         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
13112         {
13113             p_data = &frame_set->tr_particle_data[i];
13114             if(p_data->block_id == block_id)
13115             {
13116                 strncpy(name, p_data->block_name, max_len);
13117                 name[max_len - 1] = '\0';
13118                 return(TNG_SUCCESS);
13119             }
13120         }
13121     }
13122     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
13123     {
13124         for(i = 0; i < frame_set->n_data_blocks; i++)
13125         {
13126             np_data = &frame_set->tr_data[i];
13127             if(np_data->block_id == block_id)
13128             {
13129                 strncpy(name, np_data->block_name, max_len);
13130                 name[max_len - 1] = '\0';
13131                 return(TNG_SUCCESS);
13132             }
13133         }
13134     }
13135
13136     return(TNG_FAILURE);
13137 }
13138
13139 tng_function_status DECLSPECDLLEXPORT tng_data_block_dependency_get
13140                 (const tng_trajectory_t tng_data,
13141                  int64_t block_id,
13142                  int *block_dependency)
13143 {
13144     int64_t i;
13145     tng_function_status stat;
13146     tng_particle_data_t p_data;
13147     tng_non_particle_data_t np_data;
13148
13149     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13150     TNG_ASSERT(block_dependency, "TNG library: block_dependency must not be a NULL pointer.");
13151
13152     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
13153     {
13154         p_data = &tng_data->non_tr_particle_data[i];
13155         if(p_data->block_id == block_id)
13156         {
13157             *block_dependency = TNG_PARTICLE_DEPENDENT;
13158             return(TNG_SUCCESS);
13159         }
13160     }
13161     for(i = 0; i < tng_data->n_data_blocks; i++)
13162     {
13163         np_data = &tng_data->non_tr_data[i];
13164         if(np_data->block_id == block_id)
13165         {
13166             *block_dependency = 0;
13167             return(TNG_SUCCESS);
13168         }
13169     }
13170
13171     stat = tng_particle_data_find(tng_data, block_id, &p_data);
13172     if(stat == TNG_SUCCESS)
13173     {
13174         *block_dependency = TNG_PARTICLE_DEPENDENT + TNG_FRAME_DEPENDENT;
13175         return(TNG_SUCCESS);
13176     }
13177     else
13178     {
13179         stat = tng_data_find(tng_data, block_id, &np_data);
13180         if(stat == TNG_SUCCESS)
13181         {
13182             *block_dependency = TNG_FRAME_DEPENDENT;
13183             return(TNG_SUCCESS);
13184         }
13185         else
13186         {
13187             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
13188             if(stat != TNG_SUCCESS)
13189             {
13190                 return(stat);
13191             }
13192             stat = tng_particle_data_find(tng_data, block_id, &p_data);
13193             if(stat == TNG_SUCCESS)
13194             {
13195                 *block_dependency = TNG_PARTICLE_DEPENDENT + TNG_FRAME_DEPENDENT;
13196                 return(TNG_SUCCESS);
13197             }
13198             else
13199             {
13200                 stat = tng_data_find(tng_data, block_id, &np_data);
13201                 if(stat == TNG_SUCCESS)
13202                 {
13203                     *block_dependency = TNG_FRAME_DEPENDENT;
13204                     return(TNG_SUCCESS);
13205                 }
13206             }
13207         }
13208     }
13209
13210     return(TNG_FAILURE);
13211 }
13212
13213 tng_function_status DECLSPECDLLEXPORT tng_data_block_num_values_per_frame_get
13214                 (const tng_trajectory_t tng_data,
13215                  int64_t block_id,
13216                  int64_t *n_values_per_frame)
13217 {
13218     int64_t i;
13219     tng_function_status stat;
13220     tng_particle_data_t p_data;
13221     tng_non_particle_data_t np_data;
13222
13223     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13224     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
13225
13226     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
13227     {
13228         p_data = &tng_data->non_tr_particle_data[i];
13229         if(p_data->block_id == block_id)
13230         {
13231             *n_values_per_frame = p_data->n_values_per_frame;
13232             return(TNG_SUCCESS);
13233         }
13234     }
13235     for(i = 0; i < tng_data->n_data_blocks; i++)
13236     {
13237         np_data = &tng_data->non_tr_data[i];
13238         if(np_data->block_id == block_id)
13239         {
13240             *n_values_per_frame = np_data->n_values_per_frame;
13241             return(TNG_SUCCESS);
13242         }
13243     }
13244
13245     stat = tng_particle_data_find(tng_data, block_id, &p_data);
13246     if(stat == TNG_SUCCESS)
13247     {
13248         *n_values_per_frame = p_data->n_values_per_frame;
13249         return(TNG_SUCCESS);
13250     }
13251     else
13252     {
13253         stat = tng_data_find(tng_data, block_id, &np_data);
13254         if(stat == TNG_SUCCESS)
13255         {
13256             *n_values_per_frame = np_data->n_values_per_frame;
13257             return(TNG_SUCCESS);
13258         }
13259         else
13260         {
13261             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
13262             if(stat != TNG_SUCCESS)
13263             {
13264                 return(stat);
13265             }
13266             stat = tng_particle_data_find(tng_data, block_id, &p_data);
13267             if(stat == TNG_SUCCESS)
13268             {
13269                 *n_values_per_frame = p_data->n_values_per_frame;
13270                 return(TNG_SUCCESS);
13271             }
13272             else
13273             {
13274                 stat = tng_data_find(tng_data, block_id, &np_data);
13275                 if(stat == TNG_SUCCESS)
13276                 {
13277                     *n_values_per_frame = np_data->n_values_per_frame;
13278                     return(TNG_SUCCESS);
13279                 }
13280             }
13281         }
13282     }
13283
13284     return(TNG_FAILURE);
13285 }
13286
13287 tng_function_status DECLSPECDLLEXPORT tng_frame_data_write
13288                 (tng_trajectory_t tng_data,
13289                  const int64_t frame_nr,
13290                  const int64_t block_id,
13291                  const void *values,
13292                  const char hash_mode)
13293 {
13294     int64_t header_pos, file_pos;
13295     int64_t output_file_len, n_values_per_frame, size, contents_size;
13296     int64_t header_size, temp_first, temp_last;
13297     int64_t i, last_frame;
13298     long temp_current;
13299     tng_gen_block_t block;
13300     tng_trajectory_frame_set_t frame_set;
13301     FILE *temp = tng_data->input_file;
13302     struct tng_non_particle_data data;
13303     tng_function_status stat;
13304     char dependency, sparse_data, datatype;
13305     void *copy;
13306
13307     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13308     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
13309     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer.");
13310
13311     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
13312     {
13313         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
13314                __FILE__, __LINE__);
13315         return(TNG_CRITICAL);
13316     }
13317
13318     temp_first = tng_data->first_trajectory_frame_set_input_file_pos;
13319     temp_last = tng_data->last_trajectory_frame_set_input_file_pos;
13320     temp_current = tng_data->current_trajectory_frame_set_input_file_pos;
13321     tng_data->first_trajectory_frame_set_input_file_pos =
13322     tng_data->first_trajectory_frame_set_output_file_pos;
13323     tng_data->last_trajectory_frame_set_input_file_pos =
13324     tng_data->last_trajectory_frame_set_output_file_pos;
13325     tng_data->current_trajectory_frame_set_input_file_pos =
13326     tng_data->current_trajectory_frame_set_output_file_pos;
13327
13328     tng_data->input_file = tng_data->output_file;
13329
13330     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
13331
13332     frame_set = &tng_data->current_trajectory_frame_set;
13333
13334     if(stat != TNG_SUCCESS)
13335     {
13336         last_frame = frame_set->first_frame +
13337                      frame_set->n_frames - 1;
13338         /* If the wanted frame would be in the frame set after the last
13339             * frame set create a new frame set. */
13340         if(stat == TNG_FAILURE &&
13341             last_frame < frame_nr)
13342 /*           (last_frame < frame_nr &&
13343             tng_data->current_trajectory_frame_set.first_frame +
13344             tng_data->frame_set_n_frames >= frame_nr))*/
13345         {
13346             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
13347             {
13348                 last_frame = frame_nr - 1;
13349             }
13350             tng_frame_set_new(tng_data,
13351                               last_frame+1,
13352                               tng_data->frame_set_n_frames);
13353             file_pos = ftell(tng_data->output_file);
13354             fseek(tng_data->output_file, 0, SEEK_END);
13355             output_file_len = ftell(tng_data->output_file);
13356             fseek(tng_data->output_file, (long)file_pos, SEEK_SET);
13357
13358             /* Read mapping blocks from the last frame set */
13359             tng_block_init(&block);
13360
13361             stat = tng_block_header_read(tng_data, block);
13362             while(file_pos < output_file_len &&
13363                   stat != TNG_CRITICAL &&
13364                   block->id != TNG_TRAJECTORY_FRAME_SET)
13365             {
13366                 if(block->id == TNG_PARTICLE_MAPPING)
13367                 {
13368                     tng_trajectory_mapping_block_read(tng_data, block,
13369                                                       hash_mode);
13370                 }
13371                 else
13372                 {
13373                     fseek(tng_data->output_file, (long)block->block_contents_size,
13374                         SEEK_CUR);
13375                 }
13376                 file_pos = ftell(tng_data->output_file);
13377                 if(file_pos < output_file_len)
13378                 {
13379                     stat = tng_block_header_read(tng_data, block);
13380                 }
13381             }
13382
13383             tng_block_destroy(&block);
13384             /* Write the frame set to disk */
13385             if(tng_frame_set_write(tng_data, hash_mode) != TNG_SUCCESS)
13386             {
13387                 fprintf(stderr, "TNG library: Error writing frame set. %s: %d\n", __FILE__, __LINE__);
13388                 return(TNG_CRITICAL);
13389             }
13390         }
13391         else
13392         {
13393             tng_data->input_file = temp;
13394             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13395             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13396             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13397             return(stat);
13398         }
13399     }
13400
13401     tng_block_init(&block);
13402
13403     file_pos = tng_data->current_trajectory_frame_set_output_file_pos;
13404
13405     fseek(tng_data->output_file, 0, SEEK_END);
13406     output_file_len = ftell(tng_data->output_file);
13407     fseek(tng_data->output_file, (long)file_pos, SEEK_SET);
13408
13409     /* Read past the frame set block first */
13410     stat = tng_block_header_read(tng_data, block);
13411     if(stat == TNG_CRITICAL)
13412     {
13413         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
13414                file_pos, __FILE__, __LINE__);
13415         tng_block_destroy(&block);
13416         tng_data->input_file = temp;
13417
13418         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13419         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13420         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13421         return(stat);
13422     }
13423     fseek(tng_data->output_file, (long)block->block_contents_size,
13424             SEEK_CUR);
13425
13426     /* Read all block headers until next frame set block or
13427      * until the wanted block id is found */
13428     stat = tng_block_header_read(tng_data, block);
13429     while(file_pos < output_file_len &&
13430             stat != TNG_CRITICAL &&
13431             block->id != block_id &&
13432             block->id != TNG_TRAJECTORY_FRAME_SET)
13433     {
13434         fseek(tng_data->output_file, (long)block->block_contents_size, SEEK_CUR);
13435         file_pos = ftell(tng_data->output_file);
13436         if(file_pos < output_file_len)
13437         {
13438             stat = tng_block_header_read(tng_data, block);
13439         }
13440     }
13441     if(stat == TNG_CRITICAL)
13442     {
13443         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
13444                file_pos, __FILE__, __LINE__);
13445         tng_block_destroy(&block);
13446         tng_data->input_file = temp;
13447         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13448         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13449         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13450         return(stat);
13451     }
13452
13453     contents_size = block->block_contents_size;
13454     header_size = block->header_contents_size;
13455
13456     header_pos = ftell(tng_data->output_file) - header_size;
13457     frame_set = &tng_data->current_trajectory_frame_set;
13458
13459     if(fread(&datatype, sizeof(datatype), 1, tng_data->input_file) == 0)
13460     {
13461         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13462         tng_block_destroy(&block);
13463         return(TNG_CRITICAL);
13464     }
13465     if(fread(&dependency, sizeof(dependency), 1, tng_data->input_file) == 0)
13466     {
13467         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13468         tng_block_destroy(&block);
13469         return(TNG_CRITICAL);
13470     }
13471     data.datatype = datatype;
13472
13473     if(!(dependency & TNG_FRAME_DEPENDENT) ||
13474        (dependency & TNG_PARTICLE_DEPENDENT))
13475     {
13476         tng_block_destroy(&block);
13477         tng_data->input_file = temp;
13478
13479         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13480         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13481         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13482         return(TNG_FAILURE);
13483     }
13484
13485     if(fread(&sparse_data, sizeof(sparse_data), 1, tng_data->input_file) == 0)
13486     {
13487         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13488         tng_block_destroy(&block);
13489         return(TNG_CRITICAL);
13490     }
13491
13492     if(fread(&data.n_values_per_frame, sizeof(data.n_values_per_frame), 1,
13493              tng_data->input_file) == 0)
13494     {
13495         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13496         tng_block_destroy(&block);
13497         return(TNG_CRITICAL);
13498     }
13499     if(tng_data->output_endianness_swap_func_64)
13500     {
13501         if(tng_data->output_endianness_swap_func_64(tng_data,
13502             &data.n_values_per_frame)
13503             != TNG_SUCCESS)
13504         {
13505             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13506                     __FILE__, __LINE__);
13507         }
13508     }
13509
13510     if(fread(&data.codec_id, sizeof(data.codec_id), 1,
13511              tng_data->input_file) == 0)
13512     {
13513         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13514         tng_block_destroy(&block);
13515         return(TNG_CRITICAL);
13516     }
13517     if(tng_data->output_endianness_swap_func_64)
13518     {
13519         if(tng_data->output_endianness_swap_func_64(tng_data,
13520             &data.codec_id)
13521             != TNG_SUCCESS)
13522         {
13523             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13524                     __FILE__, __LINE__);
13525         }
13526     }
13527
13528     if(data.codec_id != TNG_UNCOMPRESSED)
13529     {
13530         if(fread(&data.compression_multiplier,
13531                  sizeof(data.compression_multiplier), 1, tng_data->input_file)
13532             == 0)
13533         {
13534             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13535             tng_block_destroy(&block);
13536             return(TNG_CRITICAL);
13537         }
13538         if(tng_data->output_endianness_swap_func_64)
13539         {
13540             if(tng_data->output_endianness_swap_func_64(tng_data,
13541                 (int64_t *)&data.compression_multiplier)
13542                 != TNG_SUCCESS)
13543             {
13544                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13545                         __FILE__, __LINE__);
13546             }
13547         }
13548     }
13549     else
13550     {
13551         data.compression_multiplier = 1;
13552     }
13553
13554     if(sparse_data)
13555     {
13556         if(fread(&data.first_frame_with_data, sizeof(data.first_frame_with_data),
13557                  1, tng_data->input_file) == 0)
13558         {
13559             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13560             tng_block_destroy(&block);
13561             return(TNG_CRITICAL);
13562         }
13563         if(tng_data->output_endianness_swap_func_64)
13564         {
13565             if(tng_data->output_endianness_swap_func_64(tng_data,
13566                 &data.first_frame_with_data)
13567                 != TNG_SUCCESS)
13568             {
13569                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13570                         __FILE__, __LINE__);
13571             }
13572         }
13573
13574         if(fread(&data.stride_length, sizeof(data.stride_length),
13575                  1, tng_data->input_file) == 0)
13576         {
13577             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13578             tng_block_destroy(&block);
13579             return(TNG_CRITICAL);
13580         }
13581         if(tng_data->output_endianness_swap_func_64)
13582         {
13583             if(tng_data->output_endianness_swap_func_64(tng_data,
13584                 &data.stride_length)
13585                 != TNG_SUCCESS)
13586             {
13587                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13588                         __FILE__, __LINE__);
13589             }
13590         }
13591     }
13592     else
13593     {
13594         data.first_frame_with_data = 0;
13595         data.stride_length = 1;
13596     }
13597     data.n_frames = tng_data->current_trajectory_frame_set.n_frames;
13598
13599     tng_data->input_file = temp;
13600
13601     tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13602     tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13603     tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13604
13605     switch(data.datatype)
13606     {
13607         case(TNG_INT_DATA):
13608             size = sizeof(int64_t);
13609             break;
13610         case(TNG_FLOAT_DATA):
13611             size = sizeof(float);
13612             break;
13613         case(TNG_DOUBLE_DATA):
13614             size = sizeof(double);
13615             break;
13616         default:
13617             fprintf(stderr, "TNG library: Cannot calculate writing locations. %s: %d.\n", __FILE__,
13618                    __LINE__);
13619             tng_block_destroy(&block);
13620             return(TNG_FAILURE);
13621     }
13622
13623     n_values_per_frame = data.n_values_per_frame;
13624
13625     file_pos = (frame_nr - tng_max_i64(frame_set->first_frame,
13626                                data.first_frame_with_data)) /
13627                 data.stride_length;
13628     file_pos *= size * n_values_per_frame;
13629
13630     if(file_pos > contents_size)
13631     {
13632         fprintf(stderr, "TNG library: Attempting to write outside the block. %s: %d\n", __FILE__,
13633                __LINE__);
13634         tng_block_destroy(&block);
13635         return(TNG_FAILURE);
13636     }
13637
13638     fseek(tng_data->output_file, (long)file_pos, SEEK_CUR);
13639
13640     /* If the endianness is not big endian the data needs to be swapped */
13641     if((data.datatype == TNG_INT_DATA ||
13642         data.datatype == TNG_DOUBLE_DATA) &&
13643        tng_data->output_endianness_swap_func_64)
13644     {
13645         copy = malloc(n_values_per_frame * size);
13646         memcpy(copy, values, n_values_per_frame * size);
13647         for(i = 0; i < n_values_per_frame; i++)
13648         {
13649             if(tng_data->output_endianness_swap_func_64(tng_data,
13650                 (int64_t *)copy+i)
13651                 != TNG_SUCCESS)
13652             {
13653                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13654                         __FILE__, __LINE__);
13655             }
13656         }
13657         fwrite(copy, n_values_per_frame, size,
13658                tng_data->output_file);
13659         free(copy);
13660     }
13661     else if(data.datatype == TNG_FLOAT_DATA &&
13662             tng_data->output_endianness_swap_func_32)
13663     {
13664         copy = malloc(n_values_per_frame * size);
13665         memcpy(copy, values, n_values_per_frame * size);
13666         for(i = 0; i < n_values_per_frame; i++)
13667         {
13668             if(tng_data->output_endianness_swap_func_32(tng_data,
13669                 (int32_t *)copy+i)
13670                 != TNG_SUCCESS)
13671             {
13672                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13673                         __FILE__, __LINE__);
13674             }
13675         }
13676         fwrite(copy, n_values_per_frame, size,
13677                tng_data->output_file);
13678         free(copy);
13679     }
13680
13681     else
13682     {
13683         fwrite(values, n_values_per_frame, size, tng_data->output_file);
13684     }
13685
13686     fflush(tng_data->output_file);
13687
13688     /* Update the number of written frames in the frame set. */
13689     if(frame_nr - frame_set->first_frame + 1 > frame_set->n_written_frames)
13690     {
13691         frame_set->n_written_frames = frame_nr - frame_set->first_frame + 1;
13692     }
13693
13694     /* If the last frame has been written update the hash */
13695     if(hash_mode == TNG_USE_HASH && (frame_nr + data.stride_length -
13696        data.first_frame_with_data) >=
13697        frame_set->n_frames)
13698     {
13699         tng_md5_hash_update(tng_data, block, header_pos, header_pos +
13700                             header_size);
13701     }
13702
13703     tng_block_destroy(&block);
13704
13705     return(TNG_SUCCESS);
13706 }
13707
13708 tng_function_status DECLSPECDLLEXPORT tng_frame_particle_data_write
13709                 (tng_trajectory_t tng_data,
13710                  const int64_t frame_nr,
13711                  const int64_t block_id,
13712                  const int64_t val_first_particle,
13713                  const int64_t val_n_particles,
13714                  const void *values,
13715                  const char hash_mode)
13716 {
13717     int64_t header_pos, file_pos, tot_n_particles;
13718     int64_t output_file_len, n_values_per_frame, size, contents_size;
13719     int64_t header_size, temp_first, temp_last;
13720     int64_t mapping_block_end_pos, num_first_particle, block_n_particles;
13721     int64_t i, last_frame;
13722     long temp_current;
13723     tng_gen_block_t block;
13724     tng_trajectory_frame_set_t frame_set;
13725     FILE *temp = tng_data->input_file;
13726     struct tng_particle_data data;
13727     tng_function_status stat;
13728     tng_particle_mapping_t mapping;
13729     char dependency, sparse_data, datatype;
13730     void *copy;
13731
13732     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13733     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
13734     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer.");
13735     TNG_ASSERT(val_first_particle >= 0, "TNG library: val_first_particle must be >= 0.");
13736     TNG_ASSERT(val_n_particles >= 0, "TNG library: val_n_particles must be >= 0.");
13737
13738     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
13739     {
13740         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
13741                __FILE__, __LINE__);
13742         return(TNG_CRITICAL);
13743     }
13744
13745     temp_first = tng_data->first_trajectory_frame_set_input_file_pos;
13746     temp_last = tng_data->last_trajectory_frame_set_input_file_pos;
13747     temp_current = tng_data->current_trajectory_frame_set_input_file_pos;
13748     tng_data->first_trajectory_frame_set_input_file_pos =
13749     tng_data->first_trajectory_frame_set_output_file_pos;
13750     tng_data->last_trajectory_frame_set_input_file_pos =
13751     tng_data->last_trajectory_frame_set_output_file_pos;
13752     tng_data->current_trajectory_frame_set_input_file_pos =
13753     tng_data->current_trajectory_frame_set_output_file_pos;
13754
13755     tng_data->input_file = tng_data->output_file;
13756
13757     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
13758
13759     frame_set = &tng_data->current_trajectory_frame_set;
13760
13761     if(stat != TNG_SUCCESS)
13762     {
13763         last_frame = frame_set->first_frame +
13764                      frame_set->n_frames - 1;
13765 /*         fprintf(stderr, "TNG library: Frame %"PRId64" not found. Last frame: %"PRId64"\n", frame_nr,
13766                   last_frame); */
13767         /* If the wanted frame would be in the frame set after the last
13768          * frame set create a new frame set. */
13769         if(stat == TNG_FAILURE &&
13770            (last_frame < frame_nr &&
13771             last_frame + tng_data->frame_set_n_frames >= frame_nr))
13772         {
13773             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
13774             {
13775                 last_frame = frame_nr - 1;
13776             }
13777             tng_frame_set_new(tng_data,
13778                               last_frame+1,
13779                               tng_data->frame_set_n_frames);
13780
13781             file_pos = ftell(tng_data->output_file);
13782             fseek(tng_data->output_file, 0, SEEK_END);
13783             output_file_len = ftell(tng_data->output_file);
13784             fseek(tng_data->output_file, (long)file_pos, SEEK_SET);
13785
13786             /* Read mapping blocks from the last frame set */
13787             tng_block_init(&block);
13788
13789             stat = tng_block_header_read(tng_data, block);
13790             while(file_pos < output_file_len &&
13791                   stat != TNG_CRITICAL &&
13792                   block->id != TNG_TRAJECTORY_FRAME_SET)
13793             {
13794                 if(block->id == TNG_PARTICLE_MAPPING)
13795                 {
13796                     tng_trajectory_mapping_block_read(tng_data, block,
13797                                                       hash_mode);
13798                 }
13799                 else
13800                 {
13801                     fseek(tng_data->output_file, (long)block->block_contents_size,
13802                         SEEK_CUR);
13803                 }
13804                 file_pos = ftell(tng_data->output_file);
13805                 if(file_pos < output_file_len)
13806                 {
13807                     stat = tng_block_header_read(tng_data, block);
13808                 }
13809             }
13810
13811             tng_block_destroy(&block);
13812             /* Write the frame set to disk */
13813             if(tng_frame_set_write(tng_data, hash_mode) != TNG_SUCCESS)
13814             {
13815                 fprintf(stderr, "TNG library: Error writing frame set. %s: %d\n", __FILE__, __LINE__);
13816                 exit(1);
13817             }
13818         }
13819         else
13820         {
13821             tng_data->input_file = temp;
13822             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13823             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13824             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13825             return(stat);
13826         }
13827     }
13828
13829
13830     tng_block_init(&block);
13831
13832     file_pos = tng_data->current_trajectory_frame_set_output_file_pos;
13833
13834     fseek(tng_data->output_file, 0, SEEK_END);
13835     output_file_len = ftell(tng_data->output_file);
13836     fseek(tng_data->output_file, (long)file_pos, SEEK_SET);
13837
13838     /* Read past the frame set block first */
13839     stat = tng_block_header_read(tng_data, block);
13840     if(stat == TNG_CRITICAL)
13841     {
13842         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
13843                file_pos, __FILE__, __LINE__);
13844         tng_block_destroy(&block);
13845         tng_data->input_file = temp;
13846
13847         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13848         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13849         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13850         return(stat);
13851     }
13852     fseek(tng_data->output_file, (long)block->block_contents_size,
13853             SEEK_CUR);
13854
13855     if(tng_data->var_num_atoms_flag)
13856     {
13857         tot_n_particles = frame_set->n_particles;
13858     }
13859     else
13860     {
13861         tot_n_particles = tng_data->n_particles;
13862     }
13863
13864     if(val_n_particles < tot_n_particles)
13865     {
13866         mapping_block_end_pos = -1;
13867         /* Read all mapping blocks to find the right place to put the data */
13868         stat = tng_block_header_read(tng_data, block);
13869         while(file_pos < output_file_len &&
13870                 stat != TNG_CRITICAL &&
13871                 block->id != TNG_TRAJECTORY_FRAME_SET)
13872         {
13873             if(block->id == TNG_PARTICLE_MAPPING)
13874             {
13875                 tng_trajectory_mapping_block_read(tng_data, block, hash_mode);
13876             }
13877             else
13878             {
13879                 fseek(tng_data->output_file, (long)block->block_contents_size,
13880                       SEEK_CUR);
13881             }
13882             file_pos = ftell(tng_data->output_file);
13883             if(block->id == TNG_PARTICLE_MAPPING)
13884             {
13885                 mapping = &frame_set->mappings[frame_set->n_mapping_blocks - 1];
13886                 if(val_first_particle >= mapping->num_first_particle &&
13887                    val_first_particle < mapping->num_first_particle +
13888                    mapping->n_particles &&
13889                    val_first_particle + val_n_particles <=
13890                    mapping->num_first_particle + mapping->n_particles)
13891                 {
13892                     mapping_block_end_pos = file_pos;
13893                 }
13894             }
13895             if(file_pos < output_file_len)
13896             {
13897                 stat = tng_block_header_read(tng_data, block);
13898             }
13899         }
13900         if(stat == TNG_CRITICAL)
13901         {
13902             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
13903                    file_pos, __FILE__, __LINE__);
13904             tng_block_destroy(&block);
13905             tng_data->input_file = temp;
13906
13907             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13908             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13909             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13910             return(stat);
13911         }
13912         if(mapping_block_end_pos < 0)
13913         {
13914             tng_block_destroy(&block);
13915             tng_data->input_file = temp;
13916
13917             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13918             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13919             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13920             return(TNG_FAILURE);
13921         }
13922         fseek(tng_data->output_file, (long)mapping_block_end_pos, SEEK_SET);
13923     }
13924
13925     /* Read all block headers until next frame set block or
13926      * until the wanted block id is found */
13927     stat = tng_block_header_read(tng_data, block);
13928     while(file_pos < output_file_len &&
13929             stat != TNG_CRITICAL &&
13930             block->id != block_id &&
13931             block->id != TNG_PARTICLE_MAPPING &&
13932             block->id != TNG_TRAJECTORY_FRAME_SET)
13933     {
13934         fseek(tng_data->output_file, (long)block->block_contents_size, SEEK_CUR);
13935         file_pos = ftell(tng_data->output_file);
13936         if(file_pos < output_file_len)
13937         {
13938             stat = tng_block_header_read(tng_data, block);
13939         }
13940     }
13941     if(stat == TNG_CRITICAL)
13942     {
13943         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
13944                 file_pos, __FILE__, __LINE__);
13945         tng_block_destroy(&block);
13946         tng_data->input_file = temp;
13947
13948         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13949         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13950         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13951         return(stat);
13952     }
13953
13954     contents_size = block->block_contents_size;
13955     header_size = block->header_contents_size;
13956
13957     header_pos = ftell(tng_data->output_file) - header_size;
13958     frame_set = &tng_data->current_trajectory_frame_set;
13959
13960     if(fread(&datatype, sizeof(datatype), 1, tng_data->input_file) == 0)
13961     {
13962         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13963         tng_block_destroy(&block);
13964         return(TNG_CRITICAL);
13965     }
13966
13967     data.datatype = datatype;
13968
13969     if(fread(&dependency, sizeof(dependency), 1, tng_data->input_file) == 0)
13970     {
13971         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13972         tng_block_destroy(&block);
13973         return(TNG_CRITICAL);
13974     }
13975
13976     if(!(dependency & TNG_FRAME_DEPENDENT) ||
13977        !(dependency & TNG_PARTICLE_DEPENDENT))
13978     {
13979         tng_block_destroy(&block);
13980         tng_data->input_file = temp;
13981
13982         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13983         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13984         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13985         return(TNG_FAILURE);
13986     }
13987
13988     if(fread(&sparse_data, sizeof(sparse_data), 1, tng_data->input_file) == 0)
13989     {
13990         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13991         tng_block_destroy(&block);
13992         return(TNG_CRITICAL);
13993     }
13994
13995     if(fread(&data.n_values_per_frame, sizeof(data.n_values_per_frame), 1,
13996              tng_data->input_file) == 0)
13997     {
13998         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13999         tng_block_destroy(&block);
14000         return(TNG_CRITICAL);
14001     }
14002     if(tng_data->output_endianness_swap_func_64)
14003     {
14004         if(tng_data->output_endianness_swap_func_64(tng_data,
14005             &data.n_values_per_frame)
14006             != TNG_SUCCESS)
14007         {
14008             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14009                     __FILE__, __LINE__);
14010         }
14011     }
14012
14013     if(fread(&data.codec_id, sizeof(data.codec_id), 1,
14014              tng_data->input_file) == 0)
14015     {
14016         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14017         tng_block_destroy(&block);
14018         return(TNG_CRITICAL);
14019     }
14020     if(tng_data->output_endianness_swap_func_64)
14021     {
14022         if(tng_data->output_endianness_swap_func_64(tng_data,
14023             &data.codec_id)
14024             != TNG_SUCCESS)
14025         {
14026             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14027                     __FILE__, __LINE__);
14028         }
14029     }
14030
14031     if(data.codec_id != TNG_UNCOMPRESSED)
14032     {
14033         if(fread(&data.compression_multiplier,
14034                  sizeof(data.compression_multiplier), 1, tng_data->input_file)
14035             == 0)
14036         {
14037             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14038             tng_block_destroy(&block);
14039             return(TNG_CRITICAL);
14040         }
14041
14042         if(tng_data->output_endianness_swap_func_64)
14043         {
14044             if(tng_data->output_endianness_swap_func_64(tng_data,
14045                (int64_t *)&data.compression_multiplier)
14046                 != TNG_SUCCESS)
14047             {
14048                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14049                         __FILE__, __LINE__);
14050             }
14051         }
14052     }
14053     else
14054     {
14055         data.compression_multiplier = 1;
14056     }
14057
14058     if(sparse_data)
14059     {
14060         if(fread(&data.first_frame_with_data,
14061                  sizeof(data.first_frame_with_data),
14062                  1, tng_data->input_file) == 0)
14063         {
14064             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14065             tng_block_destroy(&block);
14066             return(TNG_CRITICAL);
14067         }
14068         if(tng_data->output_endianness_swap_func_64)
14069         {
14070             if(tng_data->output_endianness_swap_func_64(tng_data,
14071                 &data.first_frame_with_data)
14072                 != TNG_SUCCESS)
14073             {
14074                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14075                         __FILE__, __LINE__);
14076             }
14077         }
14078
14079         if(fread(&data.stride_length, sizeof(data.stride_length),
14080                  1, tng_data->input_file) == 0)
14081         {
14082             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14083             tng_block_destroy(&block);
14084             return(TNG_CRITICAL);
14085         }
14086         if(tng_data->output_endianness_swap_func_64)
14087         {
14088             if(tng_data->output_endianness_swap_func_64(tng_data,
14089                 &data.stride_length)
14090                 != TNG_SUCCESS)
14091             {
14092                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14093                         __FILE__, __LINE__);
14094             }
14095         }
14096     }
14097     else
14098     {
14099         data.first_frame_with_data = 0;
14100         data.stride_length = 1;
14101     }
14102     data.n_frames = tng_data->current_trajectory_frame_set.n_frames;
14103
14104     if(fread(&num_first_particle, sizeof(num_first_particle), 1,
14105              tng_data->input_file) == 0)
14106     {
14107         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14108         tng_block_destroy(&block);
14109         return(TNG_CRITICAL);
14110     }
14111     if(tng_data->output_endianness_swap_func_64)
14112     {
14113         if(tng_data->output_endianness_swap_func_64(tng_data,
14114             &num_first_particle)
14115             != TNG_SUCCESS)
14116         {
14117             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14118                     __FILE__, __LINE__);
14119         }
14120     }
14121
14122     if(fread(&block_n_particles, sizeof(block_n_particles), 1,
14123              tng_data->input_file) == 0)
14124     {
14125         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14126         tng_block_destroy(&block);
14127         return(TNG_CRITICAL);
14128     }
14129     if(tng_data->output_endianness_swap_func_64)
14130     {
14131         if(tng_data->output_endianness_swap_func_64(tng_data,
14132             &block_n_particles)
14133             != TNG_SUCCESS)
14134         {
14135             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14136                     __FILE__, __LINE__);
14137         }
14138     }
14139
14140
14141     tng_data->input_file = temp;
14142
14143     tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14144     tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14145     tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14146
14147
14148     switch(data.datatype)
14149     {
14150         case(TNG_INT_DATA):
14151             size = sizeof(int64_t);
14152             break;
14153         case(TNG_FLOAT_DATA):
14154             size = sizeof(float);
14155             break;
14156         case(TNG_DOUBLE_DATA):
14157             size = sizeof(double);
14158             break;
14159         default:
14160             fprintf(stderr, "TNG library: Cannot calculate writing locations. %s: %d.\n", __FILE__,
14161                    __LINE__);
14162             tng_block_destroy(&block);
14163             return(TNG_FAILURE);
14164     }
14165
14166     n_values_per_frame = data.n_values_per_frame;
14167
14168     file_pos = (frame_nr - tng_max_i64(frame_set->first_frame,
14169                                data.first_frame_with_data)) /
14170                 data.stride_length;
14171     file_pos *= block_n_particles * size * n_values_per_frame;
14172
14173     if(file_pos > contents_size)
14174     {
14175         fprintf(stderr, "TNG library: Attempting to write outside the block. %s: %d\n", __FILE__,
14176                __LINE__);
14177         tng_block_destroy(&block);
14178         return(TNG_FAILURE);
14179     }
14180
14181     fseek(tng_data->output_file, (long)file_pos, SEEK_CUR);
14182
14183     /* If the endianness is not big endian the data needs to be swapped */
14184     if((data.datatype == TNG_INT_DATA ||
14185         data.datatype == TNG_DOUBLE_DATA) &&
14186        tng_data->output_endianness_swap_func_64)
14187     {
14188         copy = malloc(val_n_particles * n_values_per_frame * size);
14189         memcpy(copy, values, val_n_particles * n_values_per_frame * size);
14190         for(i = 0; i < val_n_particles * n_values_per_frame; i++)
14191         {
14192             if(tng_data->output_endianness_swap_func_64(tng_data,
14193                 (int64_t *) copy+i)
14194                 != TNG_SUCCESS)
14195             {
14196                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14197                         __FILE__, __LINE__);
14198             }
14199         }
14200         fwrite(copy, val_n_particles * n_values_per_frame, size,
14201                tng_data->output_file);
14202         free(copy);
14203     }
14204     else if(data.datatype == TNG_FLOAT_DATA &&
14205        tng_data->output_endianness_swap_func_32)
14206     {
14207         copy = malloc(val_n_particles * n_values_per_frame * size);
14208         memcpy(copy, values, val_n_particles * n_values_per_frame * size);
14209         for(i = 0; i < val_n_particles * n_values_per_frame; i++)
14210         {
14211             if(tng_data->output_endianness_swap_func_32(tng_data,
14212                 (int32_t *) copy+i)
14213                 != TNG_SUCCESS)
14214             {
14215                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14216                         __FILE__, __LINE__);
14217             }
14218         }
14219         fwrite(copy, val_n_particles * n_values_per_frame, size,
14220                tng_data->output_file);
14221         free(copy);
14222     }
14223
14224     else
14225     {
14226         fwrite(values, val_n_particles * n_values_per_frame, size,
14227                tng_data->output_file);
14228     }
14229     fflush(tng_data->output_file);
14230
14231     /* Update the number of written frames in the frame set. */
14232     if(frame_nr - frame_set->first_frame + 1 > frame_set->n_written_frames)
14233     {
14234         frame_set->n_written_frames = frame_nr - frame_set->first_frame + 1;
14235     }
14236
14237     /* If the last frame has been written update the hash */
14238     if(hash_mode == TNG_USE_HASH && (frame_nr + data.stride_length -
14239        data.first_frame_with_data) >=
14240        frame_set->n_frames)
14241     {
14242         tng_md5_hash_update(tng_data, block, header_pos, header_pos +
14243                             header_size);
14244     }
14245
14246     tng_block_destroy(&block);
14247     return(TNG_SUCCESS);
14248 }
14249
14250 static tng_function_status tng_data_values_alloc
14251                 (const tng_trajectory_t tng_data,
14252                  union data_values ***values,
14253                  const int64_t n_frames,
14254                  const int64_t n_values_per_frame,
14255                  const char type)
14256 {
14257     int64_t i;
14258     tng_function_status stat;
14259
14260     if(n_frames <= 0 || n_values_per_frame <= 0)
14261     {
14262         return(TNG_FAILURE);
14263     }
14264
14265     if(*values)
14266     {
14267         stat = tng_data_values_free(tng_data, *values, n_frames,
14268                                     n_values_per_frame,
14269                                     type);
14270         if(stat != TNG_SUCCESS)
14271         {
14272             fprintf(stderr, "TNG library: Cannot free particle data values. %s: %d\n",
14273                    __FILE__, __LINE__);
14274             return(stat);
14275         }
14276     }
14277     *values = malloc(sizeof(union data_values *) * n_frames);
14278     if(!*values)
14279     {
14280         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
14281                sizeof(union data_values **) * n_frames,
14282                __FILE__, __LINE__);
14283         return(TNG_CRITICAL);
14284
14285     }
14286
14287     for(i = n_frames; i--;)
14288     {
14289         (*values)[i] = malloc(sizeof(union data_values) *
14290                            n_values_per_frame);
14291         if(!(*values)[i])
14292         {
14293             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
14294                    sizeof(union data_values) * n_values_per_frame,
14295                    __FILE__, __LINE__);
14296             free(values);
14297             values = 0;
14298             return(TNG_CRITICAL);
14299         }
14300     }
14301     return(TNG_SUCCESS);
14302 }
14303
14304 /* FIXME: This needs ***values */
14305 tng_function_status DECLSPECDLLEXPORT tng_data_values_free
14306                 (const tng_trajectory_t tng_data,
14307                  union data_values **values,
14308                  const int64_t n_frames,
14309                  const int64_t n_values_per_frame,
14310                  const char type)
14311 {
14312     int64_t i, j;
14313     (void)tng_data;
14314
14315     if(values)
14316     {
14317         for(i = 0; i < n_frames; i++)
14318         {
14319             if(values[i])
14320             {
14321                 if(type == TNG_CHAR_DATA)
14322                 {
14323                     for(j = n_values_per_frame; j--;)
14324                     {
14325                         if(values[i][j].c)
14326                         {
14327                             free(values[i][j].c);
14328                             values[i][j].c = 0;
14329                         }
14330                     }
14331                 }
14332                 free(values[i]);
14333                 values[i] = 0;
14334             }
14335         }
14336         free(values);
14337         values = 0;
14338     }
14339
14340     return(TNG_SUCCESS);
14341 }
14342
14343 static tng_function_status tng_particle_data_values_alloc
14344                 (const tng_trajectory_t tng_data,
14345                  union data_values ****values,
14346                  const int64_t n_frames,
14347                  const int64_t n_particles,
14348                  const int64_t n_values_per_frame,
14349                  const char type)
14350 {
14351     int64_t i, j;
14352     tng_function_status stat;
14353
14354     if(n_particles == 0 || n_values_per_frame == 0)
14355     {
14356         return(TNG_FAILURE);
14357     }
14358
14359     if(*values)
14360     {
14361         stat = tng_particle_data_values_free(tng_data, *values, n_frames,
14362                                              n_particles, n_values_per_frame,
14363                                              type);
14364         if(stat != TNG_SUCCESS)
14365         {
14366             fprintf(stderr, "TNG library: Cannot free particle data values. %s: %d\n",
14367                    __FILE__, __LINE__);
14368             return(stat);
14369         }
14370     }
14371     *values = malloc(sizeof(union data_values **) * n_frames);
14372     if(!*values)
14373     {
14374         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
14375                sizeof(union data_values **) * n_frames,
14376                __FILE__, __LINE__);
14377         return(TNG_CRITICAL);
14378
14379     }
14380
14381     for(i = n_frames; i--;)
14382     {
14383         (*values)[i] = malloc(sizeof(union data_values *) *
14384                            n_particles);
14385         if(!(*values)[i])
14386         {
14387             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
14388                    sizeof(union data_values *) * n_particles,
14389                    __FILE__, __LINE__);
14390             free(*values);
14391             *values = 0;
14392             return(TNG_CRITICAL);
14393         }
14394         for(j = n_particles; j--;)
14395         {
14396             (*values)[i][j] = malloc(sizeof(union data_values) *
14397                                   n_values_per_frame);
14398             if(!(*values)[i][j])
14399             {
14400                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
14401                     sizeof(union data_values *) * n_particles,
14402                     __FILE__, __LINE__);
14403                 tng_particle_data_values_free(tng_data, *values, n_frames,
14404                                               n_particles, n_values_per_frame,
14405                                               type);
14406                 *values = 0;
14407                 return(TNG_CRITICAL);
14408             }
14409         }
14410     }
14411     return(TNG_SUCCESS);
14412 }
14413
14414 /* FIXME: This needs ****values */
14415 tng_function_status DECLSPECDLLEXPORT tng_particle_data_values_free
14416                 (const tng_trajectory_t tng_data,
14417                  union data_values ***values,
14418                  const int64_t n_frames,
14419                  const int64_t n_particles,
14420                  const int64_t n_values_per_frame,
14421                  const char type)
14422 {
14423     int64_t i, j, k;
14424     (void)tng_data;
14425
14426     if(values)
14427     {
14428         for(i = 0; i < n_frames; i++)
14429         {
14430             if(values[i])
14431             {
14432                 for(j = 0; j < n_particles; j++)
14433                 {
14434                     if(type == TNG_CHAR_DATA)
14435                     {
14436                         for(k = n_values_per_frame; k--;)
14437                         {
14438                             if(values[i][j][k].c)
14439                             {
14440                                 free(values[i][j][k].c);
14441                                 values[i][j][k].c = 0;
14442                             }
14443                         }
14444                     }
14445                     free(values[i][j]);
14446                     values[i][j] = 0;
14447                 }
14448                 free(values[i]);
14449                 values[i] = 0;
14450             }
14451         }
14452         free(values);
14453         values = 0;
14454     }
14455
14456     return(TNG_SUCCESS);
14457 }
14458
14459
14460 tng_function_status DECLSPECDLLEXPORT tng_data_get
14461                 (tng_trajectory_t tng_data,
14462                  const int64_t block_id,
14463                  union data_values ***values,
14464                  int64_t *n_frames,
14465                  int64_t *n_values_per_frame,
14466                  char *type)
14467 {
14468     int64_t i, j, file_pos, block_index;
14469     int size;
14470     size_t len;
14471     tng_non_particle_data_t data;
14472     tng_trajectory_frame_set_t frame_set;
14473     tng_gen_block_t block;
14474     tng_function_status stat;
14475
14476     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14477     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
14478     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
14479     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
14480
14481     frame_set = &tng_data->current_trajectory_frame_set;
14482
14483     block_index = -1;
14484     data = 0;
14485
14486     if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
14487     {
14488         tng_block_init(&block);
14489         file_pos = ftell(tng_data->input_file);
14490         /* Read all blocks until next frame set block */
14491         stat = tng_block_header_read(tng_data, block);
14492         while(file_pos < tng_data->input_file_len &&
14493                 stat != TNG_CRITICAL &&
14494                 block->id != TNG_TRAJECTORY_FRAME_SET)
14495         {
14496             /* Use hash by default */
14497             stat = tng_block_read_next(tng_data, block,
14498                                     TNG_USE_HASH);
14499             if(stat != TNG_CRITICAL)
14500             {
14501                 file_pos = ftell(tng_data->input_file);
14502                 if(file_pos < tng_data->input_file_len)
14503                 {
14504                     stat = tng_block_header_read(tng_data, block);
14505                 }
14506             }
14507         }
14508         tng_block_destroy(&block);
14509         if(stat == TNG_CRITICAL)
14510         {
14511             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14512                     file_pos, __FILE__, __LINE__);
14513             return(stat);
14514         }
14515
14516         for(i = frame_set->n_data_blocks; i-- ;)
14517         {
14518             data = &frame_set->tr_data[i];
14519             if(data->block_id == block_id)
14520             {
14521                 block_index = i;
14522                 break;
14523             }
14524         }
14525         if(block_index < 0)
14526         {
14527             return(TNG_FAILURE);
14528         }
14529     }
14530
14531     *n_frames = tng_max_i64(1, data->n_frames);
14532     *n_values_per_frame = data->n_values_per_frame;
14533     *type = data->datatype;
14534
14535     if(*values == 0)
14536     {
14537         if(tng_data_values_alloc(tng_data, values, *n_frames,
14538                                  *n_values_per_frame,
14539                                  *type)
14540         != TNG_SUCCESS)
14541         {
14542             return(TNG_CRITICAL);
14543         }
14544     }
14545
14546     switch(*type)
14547     {
14548     case TNG_CHAR_DATA:
14549         for(i=*n_frames; i--;)
14550         {
14551             for(j=*n_values_per_frame; j--;)
14552             {
14553                 len = strlen(data->strings[i][j]) + 1;
14554                 (*values)[i][j].c = malloc(len);
14555                 strncpy((*values)[i][j].c, data->strings[i][j], len);
14556             }
14557         }
14558         break;
14559     case TNG_INT_DATA:
14560         size = sizeof(int);
14561         for(i=*n_frames; i--;)
14562         {
14563             for(j=*n_values_per_frame; j--;)
14564             {
14565                 (*values)[i][j].i = *(int *)((char *)data->values + size *
14566                                              (i*(*n_values_per_frame) + j));
14567             }
14568         }
14569         break;
14570     case TNG_FLOAT_DATA:
14571         size = sizeof(float);
14572         for(i=*n_frames; i--;)
14573         {
14574             for(j=*n_values_per_frame; j--;)
14575             {
14576                 (*values)[i][j].f = *(float *)((char *)data->values + size *
14577                                                (i*(*n_values_per_frame) + j));
14578             }
14579         }
14580         break;
14581     case TNG_DOUBLE_DATA:
14582     default:
14583         size = sizeof(double);
14584         for(i=*n_frames; i--;)
14585         {
14586             for(j=*n_values_per_frame; j--;)
14587             {
14588                 (*values)[i][j].d = *(double *)((char *)data->values + size *
14589                                                 (i*(*n_values_per_frame) + j));
14590             }
14591         }
14592     }
14593
14594     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
14595
14596     return(TNG_SUCCESS);
14597 }
14598
14599 tng_function_status tng_data_vector_get(tng_trajectory_t tng_data,
14600                                         const int64_t block_id,
14601                                         void **values,
14602                                         int64_t *n_frames,
14603                                         int64_t *stride_length,
14604                                         int64_t *n_values_per_frame,
14605                                         char *type)
14606 {
14607     int64_t file_pos, data_size, n_frames_div, block_index;
14608     int i, size;
14609     tng_non_particle_data_t data;
14610     tng_trajectory_frame_set_t frame_set;
14611     tng_gen_block_t block;
14612     void *temp;
14613     tng_function_status stat;
14614
14615     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14616     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
14617     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
14618     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
14619     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
14620
14621     frame_set = &tng_data->current_trajectory_frame_set;
14622
14623     block_index = -1;
14624     data = 0;
14625
14626     if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
14627     {
14628         tng_block_init(&block);
14629         file_pos = ftell(tng_data->input_file);
14630         /* Read all blocks until next frame set block */
14631         stat = tng_block_header_read(tng_data, block);
14632         while(file_pos < tng_data->input_file_len &&
14633                 stat != TNG_CRITICAL &&
14634                 block->id != TNG_TRAJECTORY_FRAME_SET)
14635         {
14636             /* Use hash by default */
14637             stat = tng_block_read_next(tng_data, block,
14638                                     TNG_USE_HASH);
14639             if(stat != TNG_CRITICAL)
14640             {
14641                 file_pos = ftell(tng_data->input_file);
14642                 if(file_pos < tng_data->input_file_len)
14643                 {
14644                     stat = tng_block_header_read(tng_data, block);
14645                 }
14646             }
14647         }
14648         tng_block_destroy(&block);
14649         if(stat == TNG_CRITICAL)
14650         {
14651             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14652                     file_pos, __FILE__, __LINE__);
14653             return(stat);
14654         }
14655
14656         for(i = frame_set->n_data_blocks; i-- ;)
14657         {
14658             data = &frame_set->tr_data[i];
14659             if(data->block_id == block_id)
14660             {
14661                 block_index = i;
14662                 break;
14663             }
14664         }
14665         if(block_index < 0)
14666         {
14667             return(TNG_FAILURE);
14668         }
14669     }
14670
14671     *type = data->datatype;
14672
14673     switch(*type)
14674     {
14675     case TNG_CHAR_DATA:
14676         return(TNG_FAILURE);
14677     case TNG_INT_DATA:
14678         size = sizeof(int64_t);
14679         break;
14680     case TNG_FLOAT_DATA:
14681         size = sizeof(float);
14682         break;
14683     case TNG_DOUBLE_DATA:
14684     default:
14685         size = sizeof(double);
14686     }
14687
14688     *n_frames = data->n_frames;
14689     *n_values_per_frame = data->n_values_per_frame;
14690     *stride_length = data->stride_length;
14691     n_frames_div = (*n_frames % *stride_length) ? *n_frames / *stride_length + 1:
14692                    *n_frames / *stride_length;
14693
14694     data_size = n_frames_div * size *
14695                 *n_values_per_frame;
14696
14697     temp = realloc(*values, data_size);
14698     if(!temp)
14699     {
14700         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
14701                data_size, __FILE__, __LINE__);
14702         free(*values);
14703         *values = 0;
14704         return(TNG_CRITICAL);
14705     }
14706
14707     *values = temp;
14708
14709     memcpy(*values, data->values, data_size);
14710
14711     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
14712
14713     return(TNG_SUCCESS);
14714 }
14715
14716 tng_function_status DECLSPECDLLEXPORT tng_data_interval_get
14717                 (tng_trajectory_t tng_data,
14718                  const int64_t block_id,
14719                  const int64_t start_frame_nr,
14720                  const int64_t end_frame_nr,
14721                  const char hash_mode,
14722                  union data_values ***values,
14723                  int64_t *n_values_per_frame,
14724                  char *type)
14725 {
14726     int64_t i, j, n_frames, file_pos, current_frame_pos, first_frame;
14727     int64_t block_index;
14728     int size;
14729     size_t len;
14730     tng_non_particle_data_t data;
14731     tng_trajectory_frame_set_t frame_set;
14732     tng_gen_block_t block;
14733     tng_function_status stat;
14734
14735     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14736     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
14737     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
14738     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
14739
14740     block_index = -1;
14741
14742     frame_set = &tng_data->current_trajectory_frame_set;
14743     first_frame = frame_set->first_frame;
14744
14745     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
14746     if(stat != TNG_SUCCESS)
14747     {
14748         return(stat);
14749     }
14750
14751
14752     /* Do not re-read the frame set. */
14753     if(first_frame != frame_set->first_frame ||
14754        frame_set->n_data_blocks <= 0)
14755     {
14756         tng_block_init(&block);
14757         file_pos = ftell(tng_data->input_file);
14758         /* Read all blocks until next frame set block */
14759         stat = tng_block_header_read(tng_data, block);
14760         while(file_pos < tng_data->input_file_len &&
14761             stat != TNG_CRITICAL &&
14762             block->id != TNG_TRAJECTORY_FRAME_SET)
14763         {
14764             stat = tng_block_read_next(tng_data, block,
14765                                     hash_mode);
14766             if(stat != TNG_CRITICAL)
14767             {
14768                 file_pos = ftell(tng_data->input_file);
14769                 if(file_pos < tng_data->input_file_len)
14770                 {
14771                     stat = tng_block_header_read(tng_data, block);
14772                 }
14773             }
14774         }
14775         tng_block_destroy(&block);
14776         if(stat == TNG_CRITICAL)
14777         {
14778             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14779                     file_pos, __FILE__, __LINE__);
14780             return(stat);
14781         }
14782     }
14783
14784
14785     /* See if there is a data block of this ID.
14786      * Start checking the last read frame set */
14787     for(i = frame_set->n_data_blocks; i-- ;)
14788     {
14789         data = &frame_set->tr_data[i];
14790         if(data->block_id == block_id)
14791         {
14792             block_index = i;
14793             break;
14794         }
14795     }
14796
14797     if(block_index < 0)
14798     {
14799         fprintf(stderr, "TNG library: Could not find non-particle data block with id %"PRId64". %s: %d\n",
14800                 block_id, __FILE__, __LINE__);
14801         return(TNG_FAILURE);
14802     }
14803
14804     n_frames = end_frame_nr - start_frame_nr + 1;
14805     *n_values_per_frame = data->n_values_per_frame;
14806     *type = data->datatype;
14807
14808     if(*values == 0)
14809     {
14810         if(tng_data_values_alloc(tng_data, values, n_frames,
14811                                  *n_values_per_frame,
14812                                  *type) != TNG_SUCCESS)
14813         {
14814             return(TNG_CRITICAL);
14815         }
14816     }
14817
14818     current_frame_pos = start_frame_nr - frame_set->first_frame;
14819     /* It's not very elegant to reuse so much of the code in the different case
14820      * statements, but it's unnecessarily slow to have the switch-case block
14821      * inside the for loops. */
14822     switch(*type)
14823     {
14824     case TNG_CHAR_DATA:
14825         for(i=0; i<n_frames; i++)
14826         {
14827             if(current_frame_pos == frame_set->n_frames)
14828             {
14829                 stat = tng_frame_set_read_next(tng_data, hash_mode);
14830                 if(stat != TNG_SUCCESS)
14831                 {
14832                     return(stat);
14833                 }
14834                 current_frame_pos = 0;
14835             }
14836             for(j=*n_values_per_frame; j--;)
14837             {
14838                 len = strlen(data->strings[current_frame_pos][j]) + 1;
14839                 (*values)[i][j].c = malloc(len);
14840                 strncpy((*values)[i][j].c, data->strings[current_frame_pos][j], len);
14841             }
14842             current_frame_pos++;
14843         }
14844         break;
14845     case TNG_INT_DATA:
14846         size = sizeof(int);
14847         for(i=0; i<n_frames; i++)
14848         {
14849             if(current_frame_pos == frame_set->n_frames)
14850             {
14851                 stat = tng_frame_set_read_next(tng_data, hash_mode);
14852                 if(stat != TNG_SUCCESS)
14853                 {
14854                     return(stat);
14855                 }
14856                 current_frame_pos = 0;
14857             }
14858             for(j=*n_values_per_frame; j--;)
14859             {
14860                 (*values)[i][j].i = *(int *)((char *)data->values + size *
14861                                             (current_frame_pos *
14862                                              (*n_values_per_frame) + j));
14863             }
14864             current_frame_pos++;
14865         }
14866         break;
14867     case TNG_FLOAT_DATA:
14868         size = sizeof(float);
14869         for(i=0; i<n_frames; i++)
14870         {
14871             if(current_frame_pos == frame_set->n_frames)
14872             {
14873                 stat = tng_frame_set_read_next(tng_data, hash_mode);
14874                 if(stat != TNG_SUCCESS)
14875                 {
14876                     return(stat);
14877                 }
14878                 current_frame_pos = 0;
14879             }
14880             for(j=*n_values_per_frame; j--;)
14881             {
14882                 (*values)[i][j].f = *(float *)((char *)data->values + size *
14883                                                (current_frame_pos *
14884                                                 (*n_values_per_frame) + j));
14885             }
14886             current_frame_pos++;
14887         }
14888         break;
14889     case TNG_DOUBLE_DATA:
14890     default:
14891         size = sizeof(double);
14892         for(i=0; i<n_frames; i++)
14893         {
14894             if(current_frame_pos == frame_set->n_frames)
14895             {
14896                 stat = tng_frame_set_read_next(tng_data, hash_mode);
14897                 if(stat != TNG_SUCCESS)
14898                 {
14899                     return(stat);
14900                 }
14901                 current_frame_pos = 0;
14902             }
14903             for(j=*n_values_per_frame; j--;)
14904             {
14905                 (*values)[i][j].d = *(double *)((char *)data->values + size *
14906                                                 (current_frame_pos *
14907                                                  (*n_values_per_frame) + j));
14908             }
14909             current_frame_pos++;
14910         }
14911     }
14912
14913     data->last_retrieved_frame = end_frame_nr;
14914
14915     return(TNG_SUCCESS);
14916 }
14917
14918 tng_function_status DECLSPECDLLEXPORT tng_data_vector_interval_get
14919                 (tng_trajectory_t tng_data,
14920                  const int64_t block_id,
14921                  const int64_t start_frame_nr,
14922                  const int64_t end_frame_nr,
14923                  const char hash_mode,
14924                  void **values,
14925                  int64_t *stride_length,
14926                  int64_t *n_values_per_frame,
14927                  char *type)
14928 {
14929     int64_t n_frames, tot_n_frames, n_frames_div, n_frames_div_2, first_frame;
14930     int64_t file_pos, current_frame_pos, data_size, frame_size;
14931     int64_t last_frame_pos;
14932     int size;
14933     tng_trajectory_frame_set_t frame_set;
14934     tng_non_particle_data_t np_data;
14935     tng_gen_block_t block;
14936     void *current_values = 0, *temp;
14937     tng_function_status stat;
14938
14939     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14940     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than the end_frame_nr.");
14941     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
14942     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
14943     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
14944
14945     frame_set = &tng_data->current_trajectory_frame_set;
14946     first_frame = frame_set->first_frame;
14947
14948     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
14949     if(stat != TNG_SUCCESS)
14950     {
14951         return(stat);
14952     }
14953
14954     /* Do not re-read the frame set and only need the requested block. */
14955     /* TODO: Test that blocks are read correctly now that not all of them are read at the same time. */
14956     stat = tng_data_find(tng_data, block_id, &np_data);
14957     if(first_frame != frame_set->first_frame ||
14958        stat != TNG_SUCCESS)
14959     {
14960         tng_block_init(&block);
14961         if(stat != TNG_SUCCESS)
14962         {
14963             fseek(tng_data->input_file,
14964                   (long)tng_data->current_trajectory_frame_set_input_file_pos,
14965                   SEEK_SET);
14966             stat = tng_block_header_read(tng_data, block);
14967             if(stat != TNG_SUCCESS)
14968             {
14969                 fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n",
14970                         __FILE__, __LINE__);
14971                 return(stat);
14972             }
14973
14974             fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
14975         }
14976         file_pos = ftell(tng_data->input_file);
14977         /* Read until next frame set block */
14978         stat = tng_block_header_read(tng_data, block);
14979         while(file_pos < tng_data->input_file_len &&
14980             stat != TNG_CRITICAL &&
14981             block->id != TNG_TRAJECTORY_FRAME_SET)
14982         {
14983             if(block->id == block_id)
14984             {
14985                 stat = tng_block_read_next(tng_data, block,
14986                                         hash_mode);
14987                 if(stat != TNG_CRITICAL)
14988                 {
14989                     file_pos = ftell(tng_data->input_file);
14990                     if(file_pos < tng_data->input_file_len)
14991                     {
14992                         stat = tng_block_header_read(tng_data, block);
14993                     }
14994                 }
14995             }
14996             else
14997             {
14998                 file_pos += block->block_contents_size + block->header_contents_size;
14999                 fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
15000                 if(file_pos < tng_data->input_file_len)
15001                 {
15002                     stat = tng_block_header_read(tng_data, block);
15003                 }
15004             }
15005         }
15006         tng_block_destroy(&block);
15007         if(stat == TNG_CRITICAL)
15008         {
15009             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15010                     file_pos, __FILE__, __LINE__);
15011             return(stat);
15012         }
15013     }
15014
15015     stat = tng_data_find(tng_data, block_id, &np_data);
15016     if(stat != TNG_SUCCESS)
15017     {
15018         return(stat);
15019     }
15020
15021     stat = tng_data_vector_get(tng_data, block_id, &current_values,
15022                                &n_frames, stride_length,
15023                                n_values_per_frame, type);
15024
15025     if(stat != TNG_SUCCESS)
15026     {
15027         if(current_values)
15028         {
15029             free(current_values);
15030         }
15031         return(stat);
15032     }
15033
15034     if(n_frames == 1 && n_frames < frame_set->n_frames)
15035     {
15036         tot_n_frames = 1;
15037     }
15038     else
15039     {
15040         tot_n_frames = end_frame_nr - start_frame_nr + 1;
15041     }
15042
15043     switch(*type)
15044     {
15045     case TNG_CHAR_DATA:
15046         return(TNG_FAILURE);
15047     case TNG_INT_DATA:
15048         size = sizeof(int64_t);
15049         break;
15050     case TNG_FLOAT_DATA:
15051         size = sizeof(float);
15052         break;
15053     case TNG_DOUBLE_DATA:
15054     default:
15055         size = sizeof(double);
15056     }
15057
15058     n_frames_div = (tot_n_frames % *stride_length) ?
15059                  tot_n_frames / *stride_length + 1:
15060                  tot_n_frames / *stride_length;
15061     data_size = n_frames_div * size * (*n_values_per_frame);
15062
15063 /*     fprintf(stderr, "TNG library: size: %d, n_frames_div: %"PRId64", data_size: %"PRId64"\n",
15064               size, n_frames_div, data_size);
15065 */
15066     temp = realloc(*values, data_size);
15067     if(!temp)
15068     {
15069         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15070                data_size, __FILE__, __LINE__);
15071         free(*values);
15072         *values = 0;
15073         return(TNG_CRITICAL);
15074     }
15075
15076     *values = temp;
15077
15078     if( n_frames == 1 && n_frames < frame_set->n_frames)
15079     {
15080         memcpy(*values, current_values, size * (*n_values_per_frame));
15081     }
15082     else
15083     {
15084         current_frame_pos = start_frame_nr - frame_set->first_frame;
15085
15086         frame_size = size * (*n_values_per_frame);
15087
15088         last_frame_pos = tng_min_i64(n_frames,
15089                                      end_frame_nr - start_frame_nr);
15090
15091         n_frames_div = current_frame_pos / *stride_length;
15092         n_frames_div_2 = (last_frame_pos % *stride_length) ?
15093                        last_frame_pos / *stride_length + 1:
15094                        last_frame_pos / *stride_length;
15095         n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
15096
15097         memcpy(*values, (char *)current_values + n_frames_div * frame_size,
15098                n_frames_div_2 * frame_size);
15099
15100         current_frame_pos += n_frames - current_frame_pos;
15101
15102         while(current_frame_pos <= end_frame_nr - start_frame_nr)
15103         {
15104             stat = tng_frame_set_read_next(tng_data, hash_mode);
15105             if(stat != TNG_SUCCESS)
15106             {
15107                 if(current_values)
15108                 {
15109                     free(current_values);
15110                 }
15111                 free(*values);
15112                 *values = 0;
15113                 return(stat);
15114             }
15115
15116             stat = tng_data_vector_get(tng_data, block_id, &current_values,
15117                                     &n_frames, stride_length,
15118                                     n_values_per_frame, type);
15119
15120             if(stat != TNG_SUCCESS)
15121             {
15122                 if(current_values)
15123                 {
15124                     free(current_values);
15125                 }
15126                 free(*values);
15127                 *values = 0;
15128                 return(stat);
15129             }
15130
15131             last_frame_pos = tng_min_i64(n_frames,
15132                                          end_frame_nr - current_frame_pos);
15133
15134             n_frames_div = current_frame_pos / *stride_length;
15135             n_frames_div_2 = (last_frame_pos % *stride_length) ?
15136                            last_frame_pos / *stride_length + 1:
15137                            last_frame_pos / *stride_length;
15138             n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
15139
15140             memcpy(((char *)*values) + n_frames_div * frame_size,
15141                    current_values,
15142                    n_frames_div_2 * frame_size);
15143
15144             current_frame_pos += n_frames;
15145         }
15146     }
15147
15148     if(current_values)
15149     {
15150         free(current_values);
15151     }
15152
15153     np_data->last_retrieved_frame = end_frame_nr;
15154
15155     return(TNG_SUCCESS);
15156 }
15157
15158 tng_function_status DECLSPECDLLEXPORT tng_particle_data_get
15159                 (tng_trajectory_t tng_data,
15160                  const int64_t block_id,
15161                  union data_values ****values,
15162                  int64_t *n_frames,
15163                  int64_t *n_particles,
15164                  int64_t *n_values_per_frame,
15165                  char *type)
15166 {
15167     int64_t i, j, k, mapping, file_pos, i_step, block_index;
15168     int size;
15169     size_t len;
15170     tng_particle_data_t data;
15171     tng_trajectory_frame_set_t frame_set;
15172     tng_gen_block_t block;
15173     char block_type_flag;
15174     tng_function_status stat;
15175
15176     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15177     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
15178     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
15179     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15180     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15181
15182     frame_set = &tng_data->current_trajectory_frame_set;
15183
15184     block_index = -1;
15185     data = 0;
15186
15187     if(tng_particle_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
15188     {
15189         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
15190         {
15191             block_type_flag = TNG_TRAJECTORY_BLOCK;
15192         }
15193         else
15194         {
15195             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
15196         }
15197
15198         tng_block_init(&block);
15199         file_pos = ftell(tng_data->input_file);
15200         /* Read all blocks until next frame set block */
15201         stat = tng_block_header_read(tng_data, block);
15202         while(file_pos < tng_data->input_file_len &&
15203                 stat != TNG_CRITICAL &&
15204                 block->id != TNG_TRAJECTORY_FRAME_SET)
15205         {
15206             /* Use hash by default */
15207             stat = tng_block_read_next(tng_data, block,
15208                                     TNG_USE_HASH);
15209             if(stat != TNG_CRITICAL)
15210             {
15211                 file_pos = ftell(tng_data->input_file);
15212                 if(file_pos < tng_data->input_file_len)
15213                 {
15214                     stat = tng_block_header_read(tng_data, block);
15215                 }
15216             }
15217         }
15218         tng_block_destroy(&block);
15219         if(stat == TNG_CRITICAL)
15220         {
15221             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15222                     file_pos, __FILE__, __LINE__);
15223             return(stat);
15224         }
15225
15226         for(i = frame_set->n_particle_data_blocks; i-- ;)
15227         {
15228             data = &frame_set->tr_particle_data[i];
15229             if(data->block_id == block_id)
15230             {
15231                 block_index = i;
15232                 block_type_flag = TNG_TRAJECTORY_BLOCK;
15233                 break;
15234             }
15235         }
15236         if(block_index < 0)
15237         {
15238             return(TNG_FAILURE);
15239         }
15240     }
15241     else
15242     {
15243         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
15244         {
15245             block_type_flag = TNG_TRAJECTORY_BLOCK;
15246         }
15247         else
15248         {
15249             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
15250         }
15251     }
15252
15253     if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
15254        tng_data->var_num_atoms_flag)
15255     {
15256         *n_particles = frame_set->n_particles;
15257     }
15258     else
15259     {
15260         *n_particles = tng_data->n_particles;
15261     }
15262
15263     *n_frames = tng_max_i64(1, data->n_frames);
15264     *n_values_per_frame = data->n_values_per_frame;
15265     *type = data->datatype;
15266
15267     if(*values == 0)
15268     {
15269         if(tng_particle_data_values_alloc(tng_data, values, *n_frames,
15270                                          *n_particles, *n_values_per_frame,
15271                                          *type)
15272             != TNG_SUCCESS)
15273         {
15274             return(TNG_CRITICAL);
15275         }
15276     }
15277
15278     /* It's not very elegant to reuse so much of the code in the different case
15279      * statements, but it's unnecessarily slow to have the switch-case block
15280      * inside the for loops. */
15281     switch(*type)
15282     {
15283     case TNG_CHAR_DATA:
15284         for(i=*n_frames; i--;)
15285         {
15286             for(j=*n_particles; j--;)
15287             {
15288                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
15289                 for(k=*n_values_per_frame; k--;)
15290                 {
15291                     len = strlen(data->strings[i][j][k]) + 1;
15292                     (*values)[i][mapping][k].c = malloc(len);
15293                     strncpy((*values)[i][mapping][k].c,
15294                             data->strings[i][j][k], len);
15295                 }
15296             }
15297         }
15298         break;
15299     case TNG_INT_DATA:
15300         size = sizeof(int);
15301         i_step = (*n_particles) * (*n_values_per_frame);
15302         for(i=*n_frames; i--;)
15303         {
15304             for(j=*n_particles; j--;)
15305             {
15306                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
15307                 for(k=*n_values_per_frame; k--;)
15308                 {
15309                     (*values)[i][mapping][k].i = *(int *)
15310                                                  ((char *)data->values + size *
15311                                                  (i * i_step + j *
15312                                                   (*n_values_per_frame) + k));
15313                 }
15314             }
15315         }
15316         break;
15317     case TNG_FLOAT_DATA:
15318         size = sizeof(float);
15319         i_step = (*n_particles) * (*n_values_per_frame);
15320         for(i=*n_frames; i--;)
15321         {
15322             for(j=*n_particles; j--;)
15323             {
15324                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
15325                 for(k=*n_values_per_frame; k--;)
15326                 {
15327                     (*values)[i][mapping][k].f = *(float *)
15328                                                  ((char *)data->values + size *
15329                                                  (i * i_step + j *
15330                                                   (*n_values_per_frame) + k));
15331                 }
15332             }
15333         }
15334         break;
15335     case TNG_DOUBLE_DATA:
15336     default:
15337         size = sizeof(double);
15338         i_step = (*n_particles) * (*n_values_per_frame);
15339         for(i=*n_frames; i--;)
15340         {
15341             for(j=*n_particles; j--;)
15342             {
15343                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
15344                 for(k=*n_values_per_frame; k--;)
15345                 {
15346                     (*values)[i][mapping][k].d = *(double *)
15347                                                  ((char *)data->values + size *
15348                                                  (i * i_step + j *
15349                                                   (*n_values_per_frame) + k));
15350                 }
15351             }
15352         }
15353     }
15354
15355     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
15356
15357     return(TNG_SUCCESS);
15358 }
15359
15360 tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_get
15361                 (tng_trajectory_t tng_data,
15362                  const int64_t block_id,
15363                  void **values,
15364                  int64_t *n_frames,
15365                  int64_t *stride_length,
15366                  int64_t *n_particles,
15367                  int64_t *n_values_per_frame,
15368                  char *type)
15369 {
15370     int64_t i, j, mapping, file_pos, i_step, data_size, n_frames_div;
15371     int64_t block_index;
15372     int size;
15373     tng_particle_data_t data;
15374     tng_trajectory_frame_set_t frame_set;
15375     tng_gen_block_t block;
15376     void *temp;
15377     char block_type_flag;
15378     tng_function_status stat;
15379
15380     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15381     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
15382     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
15383     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15384     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15385
15386     frame_set = &tng_data->current_trajectory_frame_set;
15387
15388     block_index = -1;
15389     data = 0;
15390
15391     if(tng_particle_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
15392     {
15393         tng_block_init(&block);
15394         file_pos = ftell(tng_data->input_file);
15395         /* Read all blocks until next frame set block */
15396         stat = tng_block_header_read(tng_data, block);
15397         while(file_pos < tng_data->input_file_len &&
15398                 stat != TNG_CRITICAL &&
15399                 block->id != TNG_TRAJECTORY_FRAME_SET)
15400         {
15401             /* Use hash by default */
15402             stat = tng_block_read_next(tng_data, block,
15403                                     TNG_USE_HASH);
15404             if(stat != TNG_CRITICAL)
15405             {
15406                 file_pos = ftell(tng_data->input_file);
15407                 if(file_pos < tng_data->input_file_len)
15408                 {
15409                     stat = tng_block_header_read(tng_data, block);
15410                 }
15411             }
15412         }
15413         tng_block_destroy(&block);
15414         if(stat == TNG_CRITICAL)
15415         {
15416             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15417                     file_pos, __FILE__, __LINE__);
15418             return(stat);
15419         }
15420
15421         for(i = frame_set->n_particle_data_blocks; i-- ;)
15422         {
15423             data = &frame_set->tr_particle_data[i];
15424             if(data->block_id == block_id)
15425             {
15426                 block_index = i;
15427                 break;
15428             }
15429         }
15430         if(block_index < 0)
15431         {
15432             return(TNG_FAILURE);
15433         }
15434     }
15435
15436     if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
15437     {
15438         block_type_flag = TNG_TRAJECTORY_BLOCK;
15439     }
15440     else
15441     {
15442         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
15443     }
15444
15445    if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
15446       tng_data->var_num_atoms_flag)
15447     {
15448         *n_particles = frame_set->n_particles;
15449     }
15450     else
15451     {
15452         *n_particles = tng_data->n_particles;
15453     }
15454
15455     *type = data->datatype;
15456
15457     switch(*type)
15458     {
15459     case TNG_CHAR_DATA:
15460         return(TNG_FAILURE);
15461     case TNG_INT_DATA:
15462         size = sizeof(int64_t);
15463         break;
15464     case TNG_FLOAT_DATA:
15465         size = sizeof(float);
15466         break;
15467     case TNG_DOUBLE_DATA:
15468     default:
15469         size = sizeof(double);
15470     }
15471
15472     *n_frames = tng_max_i64(1, data->n_frames);
15473     *n_values_per_frame = data->n_values_per_frame;
15474     *stride_length = data->stride_length;
15475
15476     n_frames_div = (*n_frames % *stride_length) ?
15477                    *n_frames / *stride_length + 1:
15478                    *n_frames / *stride_length;
15479
15480     data_size = n_frames_div * size * (*n_particles) *
15481                 (*n_values_per_frame);
15482
15483     temp = realloc(*values, data_size);
15484     if(!temp)
15485     {
15486         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15487                data_size, __FILE__, __LINE__);
15488         free(*values);
15489         *values = 0;
15490         return(TNG_CRITICAL);
15491     }
15492
15493     *values = temp;
15494
15495     if(frame_set->n_mapping_blocks <= 0)
15496     {
15497         memcpy(*values, data->values, data_size);
15498     }
15499     else
15500     {
15501         i_step = (*n_particles) * (*n_values_per_frame);
15502         for(i = *n_frames; i--;)
15503         {
15504             for(j = *n_particles; j--;)
15505             {
15506                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
15507                 memcpy(((char *)*values) + size * (i * i_step + mapping *
15508                        (*n_values_per_frame)),
15509                        (char *)data->values + size *
15510                        (i * i_step + j * (*n_values_per_frame)),
15511                        size * (*n_values_per_frame));
15512             }
15513         }
15514     }
15515
15516     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
15517
15518     return(TNG_SUCCESS);
15519 }
15520
15521 tng_function_status DECLSPECDLLEXPORT tng_particle_data_interval_get
15522                 (tng_trajectory_t tng_data,
15523                  const int64_t block_id,
15524                  const int64_t start_frame_nr,
15525                  const int64_t end_frame_nr,
15526                  const char hash_mode,
15527                  union data_values ****values,
15528                  int64_t *n_particles,
15529                  int64_t *n_values_per_frame,
15530                  char *type)
15531 {
15532     int64_t i, j, k, mapping, n_frames, file_pos, current_frame_pos, i_step;
15533     int64_t first_frame, block_index;
15534     int size;
15535     size_t len;
15536     tng_particle_data_t data;
15537     tng_trajectory_frame_set_t frame_set;
15538     tng_gen_block_t block;
15539     char block_type_flag;
15540     tng_function_status stat;
15541
15542     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15543     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
15544     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
15545     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15546     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15547
15548     block_index = -1;
15549
15550     frame_set = &tng_data->current_trajectory_frame_set;
15551     first_frame = frame_set->first_frame;
15552
15553     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
15554     if(stat != TNG_SUCCESS)
15555     {
15556         return(stat);
15557     }
15558
15559     /* Do not re-read the frame set. */
15560     if(first_frame != frame_set->first_frame ||
15561        frame_set->n_particle_data_blocks <= 0)
15562     {
15563         tng_block_init(&block);
15564         file_pos = ftell(tng_data->input_file);
15565         /* Read all blocks until next frame set block */
15566         stat = tng_block_header_read(tng_data, block);
15567         while(file_pos < tng_data->input_file_len &&
15568                 stat != TNG_CRITICAL &&
15569                 block->id != TNG_TRAJECTORY_FRAME_SET)
15570         {
15571             stat = tng_block_read_next(tng_data, block,
15572                                     hash_mode);
15573             if(stat != TNG_CRITICAL)
15574             {
15575                 file_pos = ftell(tng_data->input_file);
15576                 if(file_pos < tng_data->input_file_len)
15577                 {
15578                     stat = tng_block_header_read(tng_data, block);
15579                 }
15580             }
15581         }
15582         tng_block_destroy(&block);
15583         if(stat == TNG_CRITICAL)
15584         {
15585             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15586                     file_pos, __FILE__, __LINE__);
15587             return(stat);
15588         }
15589     }
15590
15591     /* See if there is already a data block of this ID.
15592      * Start checking the last read frame set */
15593     for(i = frame_set->n_particle_data_blocks; i-- ;)
15594     {
15595         data = &frame_set->tr_particle_data[i];
15596         if(data->block_id == block_id)
15597         {
15598             block_index = i;
15599             block_type_flag = TNG_TRAJECTORY_BLOCK;
15600             break;
15601         }
15602     }
15603
15604     if(block_index < 0)
15605     {
15606         fprintf(stderr, "TNG library: Could not find particle data block with id %"PRId64". %s: %d\n",
15607                 block_id, __FILE__, __LINE__);
15608         return(TNG_FAILURE);
15609     }
15610
15611     if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
15612        tng_data->var_num_atoms_flag)
15613     {
15614         *n_particles = frame_set->n_particles;
15615     }
15616     else
15617     {
15618         *n_particles = tng_data->n_particles;
15619     }
15620
15621     n_frames = end_frame_nr - start_frame_nr + 1;
15622     *n_values_per_frame = data->n_values_per_frame;
15623     *type = data->datatype;
15624
15625     if(*values == 0)
15626     {
15627         if(tng_particle_data_values_alloc(tng_data, values, n_frames,
15628                                          *n_particles, *n_values_per_frame,
15629                                          *type)
15630             != TNG_SUCCESS)
15631         {
15632             return(TNG_CRITICAL);
15633         }
15634     }
15635
15636     current_frame_pos = start_frame_nr - frame_set->first_frame;
15637     /* It's not very elegant to reuse so much of the code in the different case
15638      * statements, but it's unnecessarily slow to have the switch-case block
15639      * inside the for loops. */
15640     switch(*type)
15641     {
15642     case TNG_CHAR_DATA:
15643         for(i=0; i<n_frames; i++)
15644         {
15645             if(current_frame_pos == frame_set->n_frames)
15646             {
15647                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15648                 if(stat != TNG_SUCCESS)
15649                 {
15650                     return(stat);
15651                 }
15652                 current_frame_pos = 0;
15653             }
15654             for(j=*n_particles; j--;)
15655             {
15656                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
15657                 for(k=*n_values_per_frame; k--;)
15658                 {
15659                     len = strlen(data->strings[current_frame_pos][j][k]) + 1;
15660                     (*values)[i][mapping][k].c = malloc(len);
15661                     strncpy((*values)[i][mapping][k].c, data->strings[current_frame_pos][j][k], len);
15662                 }
15663             }
15664             current_frame_pos++;
15665         }
15666         break;
15667     case TNG_INT_DATA:
15668         size = sizeof(int);
15669         i_step = (*n_particles) * (*n_values_per_frame);
15670         for(i=0; i<n_frames; i++)
15671         {
15672             if(current_frame_pos == frame_set->n_frames)
15673             {
15674                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15675                 if(stat != TNG_SUCCESS)
15676                 {
15677                     return(stat);
15678                 }
15679                 current_frame_pos = 0;
15680             }
15681             for(j=*n_particles; j--;)
15682             {
15683                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
15684                 for(k=*n_values_per_frame; k--;)
15685                 {
15686                     (*values)[i][mapping][k].i = *(int *)
15687                                                  ((char *)data->values + size *
15688                                                   (current_frame_pos *
15689                                                    i_step + j *
15690                                                    (*n_values_per_frame) + k));
15691                 }
15692             }
15693             current_frame_pos++;
15694         }
15695         break;
15696     case TNG_FLOAT_DATA:
15697         size = sizeof(float);
15698         i_step = (*n_particles) * (*n_values_per_frame);
15699         for(i=0; i<n_frames; i++)
15700         {
15701             if(current_frame_pos == frame_set->n_frames)
15702             {
15703                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15704                 if(stat != TNG_SUCCESS)
15705                 {
15706                     return(stat);
15707                 }
15708                 current_frame_pos = 0;
15709             }
15710             for(j=*n_particles; j--;)
15711             {
15712                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
15713                 for(k=*n_values_per_frame; k--;)
15714                 {
15715                     (*values)[i][mapping][k].f = *(float *)
15716                                                  ((char *)data->values + size *
15717                                                   (current_frame_pos *
15718                                                    i_step + j *
15719                                                    (*n_values_per_frame) + k));
15720                 }
15721             }
15722             current_frame_pos++;
15723         }
15724         break;
15725     case TNG_DOUBLE_DATA:
15726     default:
15727         size = sizeof(double);
15728         i_step = (*n_particles) * (*n_values_per_frame);
15729         for(i=0; i<n_frames; i++)
15730         {
15731             if(current_frame_pos == frame_set->n_frames)
15732             {
15733                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15734                 if(stat != TNG_SUCCESS)
15735                 {
15736                     return(stat);
15737                 }
15738                 current_frame_pos = 0;
15739             }
15740             for(j=*n_particles; j--;)
15741             {
15742                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
15743                 for(k=*n_values_per_frame; k--;)
15744                 {
15745                     (*values)[i][mapping][k].d = *(double *)
15746                                                  ((char *)data->values + size *
15747                                                   (current_frame_pos *
15748                                                    i_step + j *
15749                                                    (*n_values_per_frame) + k));
15750                 }
15751             }
15752             current_frame_pos++;
15753         }
15754     }
15755
15756     data->last_retrieved_frame = end_frame_nr;
15757
15758     return(TNG_SUCCESS);
15759 }
15760
15761 tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_interval_get
15762                 (tng_trajectory_t tng_data,
15763                  const int64_t block_id,
15764                  const int64_t start_frame_nr,
15765                  const int64_t end_frame_nr,
15766                  const char hash_mode,
15767                  void **values,
15768                  int64_t *n_particles,
15769                  int64_t *stride_length,
15770                  int64_t *n_values_per_frame,
15771                  char *type)
15772 {
15773     int64_t n_frames, tot_n_frames, n_frames_div, n_frames_div_2, first_frame;
15774     int64_t file_pos, current_frame_pos, last_frame_pos, data_size, frame_size;
15775     int size;
15776     tng_trajectory_frame_set_t frame_set;
15777     tng_particle_data_t p_data;
15778     tng_gen_block_t block;
15779     void *current_values = 0, *temp;
15780     tng_function_status stat;
15781
15782     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15783     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
15784     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
15785     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
15786     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15787     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15788
15789     frame_set = &tng_data->current_trajectory_frame_set;
15790     first_frame = frame_set->first_frame;
15791
15792     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
15793     if(stat != TNG_SUCCESS)
15794     {
15795         return(stat);
15796     }
15797
15798     /* Do not re-read the frame set and only need the requested block + particle mapping blocks. */
15799     /* TODO: Test that blocks are read correctly now that now all of them are read at the same time. */
15800     stat = tng_particle_data_find(tng_data, block_id, &p_data);
15801     if(first_frame != frame_set->first_frame ||
15802        stat != TNG_SUCCESS)
15803     {
15804         tng_block_init(&block);
15805         if(stat != TNG_SUCCESS)
15806         {
15807             fseek(tng_data->input_file,
15808                   (long)tng_data->current_trajectory_frame_set_input_file_pos,
15809                   SEEK_SET);
15810             stat = tng_block_header_read(tng_data, block);
15811             if(stat != TNG_SUCCESS)
15812             {
15813                 fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n",
15814                         __FILE__, __LINE__);
15815                 return(stat);
15816             }
15817
15818             fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
15819         }
15820         file_pos = ftell(tng_data->input_file);
15821         /* Read until next frame set block */
15822         stat = tng_block_header_read(tng_data, block);
15823         while(file_pos < tng_data->input_file_len &&
15824             stat != TNG_CRITICAL &&
15825             block->id != TNG_TRAJECTORY_FRAME_SET)
15826         {
15827             if(block->id == block_id || block->id == TNG_PARTICLE_MAPPING)
15828             {
15829                 stat = tng_block_read_next(tng_data, block,
15830                                         hash_mode);
15831                 if(stat != TNG_CRITICAL)
15832                 {
15833                     file_pos = ftell(tng_data->input_file);
15834                     if(file_pos < tng_data->input_file_len)
15835                     {
15836                         stat = tng_block_header_read(tng_data, block);
15837                     }
15838                 }
15839             }
15840             else
15841             {
15842                 file_pos += block->block_contents_size + block->header_contents_size;
15843                 fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
15844                 if(file_pos < tng_data->input_file_len)
15845                 {
15846                     stat = tng_block_header_read(tng_data, block);
15847                 }
15848             }
15849         }
15850         tng_block_destroy(&block);
15851         if(stat == TNG_CRITICAL)
15852         {
15853             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15854                     file_pos, __FILE__, __LINE__);
15855             return(stat);
15856         }
15857     }
15858     stat = tng_particle_data_find(tng_data, block_id, &p_data);
15859     if(stat != TNG_SUCCESS)
15860     {
15861         return(stat);
15862     }
15863
15864     stat = tng_particle_data_vector_get(tng_data, block_id, &current_values,
15865                                         &n_frames, stride_length, n_particles,
15866                                         n_values_per_frame, type);
15867
15868     if(stat != TNG_SUCCESS || *n_particles == 0)
15869     {
15870         if(current_values)
15871         {
15872             free(current_values);
15873         }
15874         return(stat);
15875     }
15876
15877     if(n_frames == 1 && n_frames < frame_set->n_frames)
15878     {
15879         tot_n_frames = 1;
15880     }
15881     else
15882     {
15883         tot_n_frames = end_frame_nr - start_frame_nr + 1;
15884     }
15885
15886     switch(*type)
15887     {
15888     case TNG_CHAR_DATA:
15889         return(TNG_FAILURE);
15890     case TNG_INT_DATA:
15891         size = sizeof(int64_t);
15892         break;
15893     case TNG_FLOAT_DATA:
15894         size = sizeof(float);
15895         break;
15896     case TNG_DOUBLE_DATA:
15897     default:
15898         size = sizeof(double);
15899     }
15900
15901     n_frames_div = (tot_n_frames % *stride_length) ?
15902                  tot_n_frames / *stride_length + 1:
15903                  tot_n_frames / *stride_length;
15904
15905     data_size = n_frames_div * size * (*n_particles) *
15906                 (*n_values_per_frame);
15907
15908     temp = realloc(*values, data_size);
15909     if(!temp)
15910     {
15911         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15912                data_size, __FILE__, __LINE__);
15913         free(*values);
15914         *values = 0;
15915         return(TNG_CRITICAL);
15916     }
15917
15918     *values = temp;
15919
15920     if( n_frames == 1 && n_frames < frame_set->n_frames)
15921     {
15922         memcpy(*values, current_values, size * (*n_particles) *
15923                (*n_values_per_frame));
15924     }
15925     else
15926     {
15927         current_frame_pos = start_frame_nr - frame_set->first_frame;
15928
15929         frame_size = size * (*n_particles) * (*n_values_per_frame);
15930
15931         last_frame_pos = tng_min_i64(n_frames,
15932                                      end_frame_nr - start_frame_nr);
15933
15934         n_frames_div = current_frame_pos / *stride_length;
15935         n_frames_div_2 = (last_frame_pos % *stride_length) ?
15936                        last_frame_pos / *stride_length + 1:
15937                        last_frame_pos / *stride_length;
15938         n_frames_div_2 = tng_max_i64(1, n_frames_div_2 + 1);
15939
15940         memcpy(*values, (char *)current_values + n_frames_div * frame_size,
15941                n_frames_div_2 * frame_size);
15942
15943         current_frame_pos += n_frames - current_frame_pos;
15944
15945         while(current_frame_pos <= end_frame_nr - start_frame_nr)
15946         {
15947             stat = tng_frame_set_read_next(tng_data, hash_mode);
15948             if(stat != TNG_SUCCESS)
15949             {
15950                 if(current_values)
15951                 {
15952                     free(current_values);
15953                 }
15954                 free(*values);
15955                 *values = 0;
15956                 return(stat);
15957             }
15958
15959             stat = tng_particle_data_vector_get(tng_data, block_id, &current_values,
15960                                                 &n_frames, stride_length, n_particles,
15961                                                 n_values_per_frame, type);
15962
15963             if(stat != TNG_SUCCESS)
15964             {
15965                 if(current_values)
15966                 {
15967                     free(current_values);
15968                 }
15969                 free(*values);
15970                 *values = 0;
15971                 return(stat);
15972             }
15973
15974             last_frame_pos = tng_min_i64(n_frames,
15975                                          end_frame_nr - current_frame_pos);
15976
15977             n_frames_div = current_frame_pos / *stride_length;
15978             n_frames_div_2 = (last_frame_pos % *stride_length) ?
15979                            last_frame_pos / *stride_length + 1:
15980                            last_frame_pos / *stride_length;
15981             n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
15982
15983             memcpy(((char *)*values) + n_frames_div * frame_size,
15984                    current_values,
15985                    n_frames_div_2 * frame_size);
15986
15987             current_frame_pos += n_frames;
15988         }
15989     }
15990
15991     if(current_values)
15992     {
15993         free(current_values);
15994     }
15995
15996     p_data->last_retrieved_frame = end_frame_nr;
15997
15998     return(TNG_SUCCESS);
15999 }
16000
16001 tng_function_status DECLSPECDLLEXPORT tng_data_get_stride_length
16002                 (const tng_trajectory_t tng_data,
16003                  const int64_t block_id,
16004                  int64_t frame,
16005                  int64_t *stride_length)
16006 {
16007     tng_function_status stat;
16008     tng_non_particle_data_t np_data;
16009     tng_particle_data_t p_data;
16010     long file_pos;
16011     int is_particle_data;
16012
16013     if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
16014     {
16015         frame = 0;
16016     }
16017
16018     if(frame >= 0)
16019     {
16020         stat = tng_frame_set_of_frame_find(tng_data, frame);
16021         if(stat != TNG_SUCCESS)
16022         {
16023             return(stat);
16024         }
16025     }
16026     stat = tng_data_find(tng_data, block_id, &np_data);
16027     if(stat != TNG_SUCCESS)
16028     {
16029         stat = tng_particle_data_find(tng_data, block_id, &p_data);
16030         if(stat != TNG_SUCCESS)
16031         {
16032             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16033             /* If no specific frame was required read until this data block is found */
16034             if(frame < 0)
16035             {
16036                 file_pos = ftell(tng_data->input_file);
16037                 while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
16038                 {
16039                     stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16040                     file_pos = ftell(tng_data->input_file);
16041                 }
16042             }
16043             if(stat != TNG_SUCCESS)
16044             {
16045                 return(stat);
16046             }
16047             stat = tng_data_find(tng_data, block_id, &np_data);
16048             if(stat != TNG_SUCCESS)
16049             {
16050                 stat = tng_particle_data_find(tng_data, block_id, &p_data);
16051                 if(stat != TNG_SUCCESS)
16052                 {
16053                     return(stat);
16054                 }
16055                 else
16056                 {
16057                     is_particle_data = 1;
16058                 }
16059             }
16060             else
16061             {
16062                 is_particle_data = 0;
16063             }
16064         }
16065         else
16066         {
16067             is_particle_data = 1;
16068         }
16069     }
16070     else
16071     {
16072         is_particle_data = 0;
16073     }
16074     if(is_particle_data)
16075     {
16076         *stride_length = p_data->stride_length;
16077     }
16078     else
16079     {
16080         *stride_length = np_data->stride_length;
16081     }
16082     return(TNG_SUCCESS);
16083 }
16084
16085 tng_function_status DECLSPECDLLEXPORT tng_time_get_str
16086                 (const tng_trajectory_t tng_data,
16087                  char *time)
16088 {
16089     struct tm *time_data;
16090     time_t secs;
16091
16092     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16093     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
16094
16095     secs = tng_data->time;
16096
16097     time_data = localtime(&secs); /* Returns a statically allocated variable. */
16098     TNG_SNPRINTF(time, TNG_MAX_DATE_STR_LEN,
16099              "%4d-%02d-%02d %02d:%02d:%02d",
16100              time_data->tm_year+1900, time_data->tm_mon+1, time_data->tm_mday,
16101              time_data->tm_hour, time_data->tm_min, time_data->tm_sec);
16102
16103     return(TNG_SUCCESS);
16104 }
16105
16106
16107 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_open
16108                 (const char *filename,
16109                  const char mode,
16110                  tng_trajectory_t *tng_data_p)
16111 {
16112     tng_function_status stat;
16113
16114     TNG_ASSERT(filename, "TNG library: filename must not be a NULL pointer.");
16115
16116     if(mode != 'r' && mode != 'w' && mode != 'a')
16117     {
16118         return(TNG_FAILURE);
16119     }
16120
16121     if(tng_trajectory_init(tng_data_p) != TNG_SUCCESS)
16122     {
16123         tng_trajectory_destroy(tng_data_p);
16124         return(TNG_CRITICAL);
16125     }
16126
16127     if(mode == 'r' || mode == 'a')
16128     {
16129         tng_input_file_set(*tng_data_p, filename);
16130
16131         /* Read the file headers */
16132         tng_file_headers_read(*tng_data_p, TNG_USE_HASH);
16133
16134         tng_num_frame_sets_get(*tng_data_p, &(*tng_data_p)->n_trajectory_frame_sets);
16135     }
16136
16137     if(mode == 'w')
16138     {
16139         tng_output_file_set(*tng_data_p, filename);
16140     }
16141     else if(mode == 'a')
16142     {
16143         fseek((*tng_data_p)->input_file,
16144                 (long)(*tng_data_p)->last_trajectory_frame_set_input_file_pos,
16145                 SEEK_SET);
16146
16147         stat = tng_frame_set_read(*tng_data_p, TNG_USE_HASH);
16148         if(stat != TNG_SUCCESS)
16149         {
16150             fprintf(stderr, "TNG library: Cannot read frame set and related blocks. %s: %d\n",
16151                    __FILE__, __LINE__);
16152         }
16153
16154         (*tng_data_p)->first_trajectory_frame_set_output_file_pos =
16155         (*tng_data_p)->first_trajectory_frame_set_input_file_pos;
16156         (*tng_data_p)->last_trajectory_frame_set_output_file_pos =
16157         (*tng_data_p)->last_trajectory_frame_set_input_file_pos;
16158         (*tng_data_p)->current_trajectory_frame_set_output_file_pos =
16159         (*tng_data_p)->current_trajectory_frame_set_input_file_pos;
16160         (*tng_data_p)->first_trajectory_frame_set_input_file_pos = -1;
16161         (*tng_data_p)->last_trajectory_frame_set_input_file_pos = -1;
16162         (*tng_data_p)->current_trajectory_frame_set_input_file_pos = -1;
16163         if((*tng_data_p)->input_file)
16164         {
16165             fclose((*tng_data_p)->input_file);
16166             (*tng_data_p)->input_file = 0;
16167         }
16168         if((*tng_data_p)->input_file_path)
16169         {
16170             free((*tng_data_p)->input_file_path);
16171             (*tng_data_p)->input_file_path = 0;
16172         }
16173         tng_output_append_file_set(*tng_data_p, filename);
16174
16175         fseek((*tng_data_p)->output_file, 0, SEEK_END);
16176     }
16177
16178     return(TNG_SUCCESS);
16179 }
16180
16181 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_close
16182                 (tng_trajectory_t *tng_data_p)
16183 {
16184     tng_trajectory_frame_set_t frame_set;
16185
16186     if(tng_data_p == 0)
16187     {
16188         fprintf(stderr, "TNG library: Empty pointer to trajectory when attempting to close. %s: %d\n",
16189                __FILE__, __LINE__);
16190         return(TNG_FAILURE);
16191     }
16192
16193     if(*tng_data_p == 0)
16194     {
16195         return(TNG_SUCCESS);
16196     }
16197
16198     frame_set = &(*tng_data_p)->current_trajectory_frame_set;
16199
16200     if(frame_set->n_unwritten_frames > 0)
16201     {
16202         frame_set->n_frames = frame_set->n_unwritten_frames;
16203         tng_frame_set_write(*tng_data_p, TNG_USE_HASH);
16204     }
16205
16206     return(tng_trajectory_destroy(tng_data_p));
16207 }
16208
16209 tng_function_status DECLSPECDLLEXPORT tng_util_time_of_frame_get
16210                 (tng_trajectory_t tng_data,
16211                  const int64_t frame_nr,
16212                  double *time)
16213 {
16214     int64_t first_frame;
16215     tng_trajectory_frame_set_t frame_set;
16216     tng_function_status stat;
16217
16218     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16219     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
16220
16221     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
16222     if(stat != TNG_SUCCESS)
16223     {
16224         fprintf(stderr, "TNG library: Cannot find frame nr %"PRId64". %s: %d\n",
16225                frame_nr, __FILE__, __LINE__);
16226         return(stat);
16227     }
16228
16229     frame_set = &tng_data->current_trajectory_frame_set;
16230     first_frame = frame_set->first_frame;
16231
16232     if(tng_data->time_per_frame <= 0)
16233     {
16234         return(TNG_FAILURE);
16235     }
16236
16237     *time = frame_set->first_frame_time + (tng_data->time_per_frame * (frame_nr - first_frame));
16238
16239     return(TNG_SUCCESS);
16240 }
16241
16242 /*
16243 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecules_get
16244                 (tng_trajectory_t tng_data,
16245                  int64_t *n_mols,
16246                  int64_t **molecule_cnt_list,
16247                  tng_molecule_t *mols)
16248 {
16249     tng_trajectory_frame_set_t frame_set;
16250
16251     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16252     TNG_ASSERT(n_mols, "TNG library: n_mols must not be a NULL pointer.");
16253
16254     *n_mols = tng_data->n_molecules;
16255
16256     frame_set = &tng_data->current_trajectory_frame_set;
16257     if(tng_data->var_num_atoms_flag && frame_set && frame_set->molecule_cnt_list)
16258     {
16259         *molecule_cnt_list = frame_set->molecule_cnt_list;
16260     }
16261     else
16262     {
16263         *molecule_cnt_list = tng_data->molecule_cnt_list;
16264     }
16265
16266     *mols = tng_data->molecules;
16267
16268     return(TNG_SUCCESS);
16269 }
16270 */
16271 /*
16272 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecule_add
16273                 (tng_trajectory_t tng_data,
16274                  const char *name,
16275                  const int64_t cnt,
16276                  tng_molecule_t *mol)
16277 {
16278     tng_function_status stat;
16279
16280     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
16281     TNG_ASSERT(cnt>=0, "TNG library: cnt must be >= 0");
16282
16283     stat = tng_molecule_add(tng_data, name, mol);
16284     if(stat != TNG_SUCCESS)
16285     {
16286         return(stat);
16287     }
16288     stat = tng_molecule_cnt_set(tng_data, *mol, cnt);
16289
16290     return(stat);
16291 }
16292 */
16293 tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_get
16294                 (tng_trajectory_t tng_data,
16295                  const tng_molecule_t mol,
16296                  int64_t *n_particles,
16297                  char ***names,
16298                  char ***types,
16299                  char ***res_names,
16300                  int64_t **res_ids,
16301                  char ***chain_names,
16302                  int64_t **chain_ids)
16303 {
16304     tng_atom_t atom;
16305     tng_residue_t res;
16306     tng_chain_t chain;
16307     int64_t i;
16308     (void)tng_data;
16309
16310     *n_particles = mol->n_atoms;
16311
16312     *names = malloc(sizeof(char *) * *n_particles);
16313     *types = malloc(sizeof(char *) * *n_particles);
16314     *res_names = malloc(sizeof(char *) * *n_particles);
16315     *chain_names = malloc(sizeof(char *) * *n_particles);
16316     *res_ids = malloc(sizeof(int64_t) * *n_particles);
16317     *chain_ids = malloc(sizeof(int64_t) * *n_particles);
16318
16319     for(i = 0; i < *n_particles; i++)
16320     {
16321         atom = &mol->atoms[i];
16322         res = atom->residue;
16323         chain = res->chain;
16324         (*names)[i] = malloc(strlen(atom->name));
16325         strcpy(*names[i], atom->name);
16326         (*types)[i] = malloc(strlen(atom->atom_type));
16327         strcpy(*types[i], atom->atom_type);
16328         (*res_names)[i] = malloc(strlen(res->name));
16329         strcpy(*res_names[i], res->name);
16330         (*chain_names)[i] = malloc(strlen(chain->name));
16331         strcpy(*chain_names[i], chain->name);
16332         (*res_ids)[i] = res->id;
16333         (*chain_ids)[i] = chain->id;
16334     }
16335
16336     return(TNG_SUCCESS);
16337 }
16338
16339 tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_set
16340                 (tng_trajectory_t tng_data,
16341                  tng_molecule_t mol,
16342                  const int64_t n_particles,
16343                  const char **names,
16344                  const char **types,
16345                  const char **res_names,
16346                  const int64_t *res_ids,
16347                  const char **chain_names,
16348                  const int64_t *chain_ids)
16349 {
16350     int64_t i;
16351     tng_chain_t chain;
16352     tng_residue_t residue;
16353     tng_atom_t atom;
16354     tng_function_status stat;
16355
16356     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16357     TNG_ASSERT(names, "TNG library: names must not be a NULL pointer");
16358     TNG_ASSERT(types, "TNG library: types must not be a NULL pointer");
16359     TNG_ASSERT(res_names, "TNG library: res_names must not be a NULL pointer");
16360     TNG_ASSERT(res_ids, "TNG library: res_ids must not be a NULL pointer");
16361     TNG_ASSERT(chain_names, "TNG library: chain_names must not be a NULL pointer");
16362     TNG_ASSERT(chain_ids, "TNG library: chain_ids must not be a NULL pointer");
16363
16364     for(i = 0; i < n_particles; i++)
16365     {
16366         if(tng_molecule_chain_find(tng_data, mol, chain_names[i], chain_ids[i],
16367            &chain) == TNG_FAILURE)
16368         {
16369             stat = tng_molecule_chain_add(tng_data, mol, chain_names[i],
16370                                           &chain);
16371             if(stat != TNG_SUCCESS)
16372             {
16373                 return(stat);
16374             }
16375         }
16376         if(tng_chain_residue_find(tng_data, chain, res_names[i], res_ids[i],
16377            &residue) == TNG_FAILURE)
16378         {
16379             stat = tng_chain_residue_add(tng_data, chain, res_names[i],
16380                                          &residue);
16381             if(stat != TNG_SUCCESS)
16382             {
16383                 return(stat);
16384             }
16385         }
16386         stat = tng_residue_atom_add(tng_data, residue, names[i], types[i], &atom);
16387         if(stat != TNG_SUCCESS)
16388         {
16389             return(stat);
16390         }
16391     }
16392     return(TNG_SUCCESS);
16393 }
16394
16395 tng_function_status DECLSPECDLLEXPORT tng_util_pos_read
16396                 (tng_trajectory_t tng_data,
16397                  float **positions, int64_t *stride_length)
16398 {
16399     int64_t n_frames, n_particles, n_values_per_frame;
16400     char type;
16401     tng_function_status stat;
16402
16403     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16404     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
16405     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
16406
16407     stat = tng_num_frames_get(tng_data, &n_frames);
16408     if(stat != TNG_SUCCESS)
16409     {
16410         return(stat);
16411     }
16412
16413     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_POSITIONS,
16414                                                  0, n_frames - 1, TNG_USE_HASH,
16415                                                  (void **)positions,
16416                                                  &n_particles,
16417                                                  stride_length,
16418                                                  &n_values_per_frame,
16419                                                  &type);
16420
16421     return(stat);
16422 }
16423
16424 tng_function_status DECLSPECDLLEXPORT tng_util_vel_read
16425                 (tng_trajectory_t tng_data,
16426                  float **velocities, int64_t *stride_length)
16427 {
16428     int64_t n_frames, n_particles, n_values_per_frame;
16429     char type;
16430     tng_function_status stat;
16431
16432     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16433     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
16434     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
16435
16436     stat = tng_num_frames_get(tng_data, &n_frames);
16437     if(stat != TNG_SUCCESS)
16438     {
16439         return(stat);
16440     }
16441
16442     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_VELOCITIES,
16443                                                  0, n_frames - 1, TNG_USE_HASH,
16444                                                  (void **)velocities,
16445                                                  &n_particles,
16446                                                  stride_length,
16447                                                  &n_values_per_frame,
16448                                                  &type);
16449
16450     return(stat);
16451 }
16452
16453 tng_function_status DECLSPECDLLEXPORT tng_util_force_read
16454                 (tng_trajectory_t tng_data,
16455                  float **forces, int64_t *stride_length)
16456 {
16457     int64_t n_frames, n_particles, n_values_per_frame;
16458     char type;
16459     tng_function_status stat;
16460
16461     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16462     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
16463     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
16464
16465     stat = tng_num_frames_get(tng_data, &n_frames);
16466     if(stat != TNG_SUCCESS)
16467     {
16468         return(stat);
16469     }
16470
16471     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_FORCES,
16472                                                  0, n_frames - 1, TNG_USE_HASH,
16473                                                  (void **)forces,
16474                                                  &n_particles,
16475                                                  stride_length,
16476                                                  &n_values_per_frame,
16477                                                  &type);
16478
16479     return(stat);
16480 }
16481
16482 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read
16483                 (tng_trajectory_t tng_data,
16484                  float **box_shape,
16485                  int64_t *stride_length)
16486 {
16487     int64_t n_frames, n_values_per_frame;
16488     char type;
16489     tng_function_status stat;
16490
16491     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16492     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
16493     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
16494
16495     stat = tng_num_frames_get(tng_data, &n_frames);
16496     if(stat != TNG_SUCCESS)
16497     {
16498         return(stat);
16499     }
16500
16501     stat = tng_data_vector_interval_get(tng_data, TNG_TRAJ_BOX_SHAPE,
16502                                         0, n_frames - 1, TNG_USE_HASH,
16503                                         (void **)box_shape,
16504                                         stride_length,
16505                                         &n_values_per_frame,
16506                                         &type);
16507
16508     return(stat);
16509 }
16510
16511 tng_function_status DECLSPECDLLEXPORT tng_util_particle_data_next_frame_read
16512                 (tng_trajectory_t tng_data,
16513                  const int64_t block_id,
16514                  void **values,
16515                  char *data_type,
16516                  int64_t *retrieved_frame_number,
16517                  double *retrieved_time)
16518 {
16519     tng_trajectory_frame_set_t frame_set;
16520     tng_particle_data_t data = 0;
16521     tng_function_status stat;
16522     int size;
16523     int64_t i, data_size, n_particles;
16524     void *temp;
16525     long file_pos;
16526
16527     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16528     TNG_ASSERT(values, "TNG library: The pointer to the values array must not be a NULL pointer");
16529     TNG_ASSERT(data_type, "TNG library: The pointer to the data type of the returned data must not be a NULL pointer");
16530     TNG_ASSERT(retrieved_frame_number, "TNG library: The pointer to the frame number of the returned data must not be a NULL pointer");
16531     TNG_ASSERT(retrieved_time, "TNG library: The pointer to the time of the returned data must not be a NULL pointer");
16532
16533     frame_set = &tng_data->current_trajectory_frame_set;
16534
16535     stat = tng_particle_data_find(tng_data, block_id, &data);
16536     if(stat != TNG_SUCCESS)
16537     {
16538         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16539         file_pos = ftell(tng_data->input_file);
16540         while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
16541         {
16542             stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16543             file_pos = ftell(tng_data->input_file);
16544         }
16545         if(stat != TNG_SUCCESS)
16546         {
16547             return(stat);
16548         }
16549         stat = tng_particle_data_find(tng_data, block_id, &data);
16550         if(stat != TNG_SUCCESS)
16551         {
16552             return(stat);
16553         }
16554     }
16555     if(data->last_retrieved_frame < 0)
16556     {
16557         fseek(tng_data->input_file,
16558               (long)tng_data->first_trajectory_frame_set_input_file_pos,
16559               SEEK_SET);
16560         stat = tng_frame_set_read(tng_data, TNG_USE_HASH);
16561         if(stat != TNG_SUCCESS)
16562         {
16563             return(stat);
16564         }
16565         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16566         if(stat != TNG_SUCCESS)
16567         {
16568             return(stat);
16569         }
16570
16571         i = data->first_frame_with_data;
16572     }
16573     else
16574     {
16575         i = data->last_retrieved_frame + data->stride_length;
16576         if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
16577         {
16578             stat = tng_frame_set_of_frame_find(tng_data, i);
16579             if(stat != TNG_SUCCESS)
16580             {
16581                 /* If the frame set search found the frame set after the starting
16582                  * frame set there is a gap in the frame sets. So, even if the frame
16583                  * was not found the next frame with data is still in the found
16584                  * frame set. */
16585                 if(stat == TNG_CRITICAL)
16586                 {
16587                     return(stat);
16588                 }
16589                 i = frame_set->first_frame;
16590             }
16591         }
16592         if(data->last_retrieved_frame < frame_set->first_frame)
16593         {
16594             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16595             if(stat != TNG_SUCCESS)
16596             {
16597                 return(stat);
16598             }
16599         }
16600     }
16601     data->last_retrieved_frame = i;
16602     *retrieved_frame_number = i;
16603     if(frame_set->first_frame_time >= 0 && tng_data->time_per_frame >= 0)
16604     {
16605         *retrieved_time = frame_set->first_frame_time +
16606                         (i - frame_set->first_frame) *
16607                         tng_data->time_per_frame;
16608     }
16609     else
16610     {
16611         *retrieved_time = 0;
16612     }
16613
16614     if(data->stride_length > 1)
16615     {
16616         i = (i - data->first_frame_with_data) / data->stride_length;
16617     }
16618     else
16619     {
16620         i = (i - frame_set->first_frame);
16621     }
16622
16623     tng_num_particles_get(tng_data, &n_particles);
16624
16625     *data_type = data->datatype;
16626
16627     switch(*data_type)
16628     {
16629     case TNG_CHAR_DATA:
16630         return(TNG_FAILURE);
16631     case TNG_INT_DATA:
16632         size = sizeof(int64_t);
16633         break;
16634     case TNG_FLOAT_DATA:
16635         size = sizeof(float);
16636         break;
16637     case TNG_DOUBLE_DATA:
16638     default:
16639         size = sizeof(double);
16640     }
16641
16642     data_size = size * n_particles * data->n_values_per_frame;
16643
16644 //     fprintf(stderr, "TNG library: TEMP: i = %"PRId64", data_size = %"PRId64", size = %d, n_particles = %"PRId64", n_values_per_frame = %"PRId64"\n",
16645 //            i, data_size, size, n_particles, data->n_values_per_frame);
16646
16647     temp = realloc(*values, data_size);
16648     if(!temp)
16649     {
16650         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
16651                data_size, __FILE__, __LINE__);
16652         free(*values);
16653         *values = 0;
16654         return(TNG_CRITICAL);
16655     }
16656
16657     *values = temp;
16658
16659     memcpy(*values, (char *)data->values + i * data_size, data_size);
16660
16661     return(TNG_SUCCESS);
16662 }
16663
16664 tng_function_status DECLSPECDLLEXPORT tng_util_non_particle_data_next_frame_read
16665                 (tng_trajectory_t tng_data,
16666                  const int64_t block_id,
16667                  void **values,
16668                  char *data_type,
16669                  int64_t *retrieved_frame_number,
16670                  double *retrieved_time)
16671 {
16672     tng_trajectory_frame_set_t frame_set;
16673     tng_non_particle_data_t data = 0;
16674     tng_function_status stat;
16675     int size;
16676     int64_t i, data_size;
16677     void *temp;
16678     long file_pos;
16679
16680     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16681     TNG_ASSERT(values, "TNG library: The pointer to the values array must not be a NULL pointer");
16682     TNG_ASSERT(data_type, "TNG library: The pointer to the data type of the returned data must not be a NULL pointer");
16683     TNG_ASSERT(retrieved_frame_number, "TNG library: The pointer to the frame number of the returned data must not be a NULL pointer");
16684     TNG_ASSERT(retrieved_time, "TNG library: The pointer to the time of the returned data must not be a NULL pointer");
16685
16686     frame_set = &tng_data->current_trajectory_frame_set;
16687
16688     stat = tng_data_find(tng_data, block_id, &data);
16689     if(stat != TNG_SUCCESS)
16690     {
16691         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16692         file_pos = ftell(tng_data->input_file);
16693         while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
16694         {
16695             stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16696             file_pos = ftell(tng_data->input_file);
16697         }
16698         if(stat != TNG_SUCCESS)
16699         {
16700             return(stat);
16701         }
16702         stat = tng_data_find(tng_data, block_id, &data);
16703         if(stat != TNG_SUCCESS)
16704         {
16705             return(stat);
16706         }
16707     }
16708     if(data->last_retrieved_frame < 0)
16709     {
16710         fseek(tng_data->input_file,
16711                 (long)tng_data->first_trajectory_frame_set_input_file_pos,
16712                 SEEK_SET);
16713         stat = tng_frame_set_read(tng_data, TNG_USE_HASH);
16714         if(stat != TNG_SUCCESS)
16715         {
16716             return(stat);
16717         }
16718         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16719         if(stat != TNG_SUCCESS)
16720         {
16721             return(stat);
16722         }
16723
16724         i = data->first_frame_with_data;
16725     }
16726     else
16727     {
16728         i = data->last_retrieved_frame + data->stride_length;
16729         if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
16730         {
16731             stat = tng_frame_set_of_frame_find(tng_data, i);
16732             if(stat != TNG_SUCCESS)
16733             {
16734                 /* If the frame set search found the frame set after the starting
16735                  * frame set there is a gap in the frame sets. So, even if the frame
16736                  * was not found the next frame with data is still in the found
16737                  * frame set. */
16738                 if(stat == TNG_CRITICAL)
16739                 {
16740                     return(stat);
16741                 }
16742                 i = frame_set->first_frame;
16743             }
16744         }
16745         if(data->last_retrieved_frame < frame_set->first_frame)
16746         {
16747             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16748             if(stat != TNG_SUCCESS)
16749             {
16750                 return(stat);
16751             }
16752         }
16753     }
16754     data->last_retrieved_frame = i;
16755     *retrieved_frame_number = i;
16756     if(frame_set->first_frame_time >= 0 && tng_data->time_per_frame >= 0)
16757     {
16758         *retrieved_time = frame_set->first_frame_time +
16759                         (i - frame_set->first_frame) *
16760                         tng_data->time_per_frame;
16761     }
16762     else
16763     {
16764         *retrieved_time = 0;
16765     }
16766
16767     if(data->stride_length > 1)
16768     {
16769         i = (i - data->first_frame_with_data) / data->stride_length;
16770     }
16771     else
16772     {
16773         i = (i - frame_set->first_frame);
16774     }
16775
16776     *data_type = data->datatype;
16777
16778     switch(*data_type)
16779     {
16780     case TNG_CHAR_DATA:
16781         return(TNG_FAILURE);
16782     case TNG_INT_DATA:
16783         size = sizeof(int64_t);
16784         break;
16785     case TNG_FLOAT_DATA:
16786         size = sizeof(float);
16787         break;
16788     case TNG_DOUBLE_DATA:
16789     default:
16790         size = sizeof(double);
16791     }
16792
16793     data_size = size * data->n_values_per_frame;
16794
16795     temp = realloc(*values, data_size);
16796     if(!temp)
16797     {
16798         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
16799                data_size, __FILE__, __LINE__);
16800         free(*values);
16801         *values = 0;
16802         return(TNG_CRITICAL);
16803     }
16804
16805     *values = temp;
16806
16807     memcpy(*values, (char *)data->values + i * data_size, data_size);
16808
16809     return(TNG_SUCCESS);
16810 }
16811
16812 tng_function_status DECLSPECDLLEXPORT tng_util_pos_read_range
16813                 (tng_trajectory_t tng_data,
16814                  const int64_t first_frame,
16815                  const int64_t last_frame,
16816                  float **positions,
16817                  int64_t *stride_length)
16818 {
16819     int64_t n_particles, n_values_per_frame;
16820     char type;
16821     tng_function_status stat;
16822
16823     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16824     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
16825     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
16826     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
16827
16828     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_POSITIONS,
16829                                                  first_frame, last_frame,
16830                                                  TNG_USE_HASH,
16831                                                  (void **)positions,
16832                                                  &n_particles,
16833                                                  stride_length,
16834                                                  &n_values_per_frame,
16835                                                  &type);
16836
16837     return(stat);
16838 }
16839
16840 tng_function_status DECLSPECDLLEXPORT tng_util_vel_read_range
16841                 (tng_trajectory_t tng_data,
16842                  const int64_t first_frame,
16843                  const int64_t last_frame,
16844                  float **velocities,
16845                  int64_t *stride_length)
16846 {
16847     int64_t n_particles, n_values_per_frame;
16848     char type;
16849     tng_function_status stat;
16850
16851     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16852     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
16853     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
16854     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
16855
16856     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_VELOCITIES,
16857                                                  first_frame, last_frame,
16858                                                  TNG_USE_HASH,
16859                                                  (void **)velocities,
16860                                                  &n_particles,
16861                                                  stride_length,
16862                                                  &n_values_per_frame,
16863                                                  &type);
16864
16865     return(stat);
16866 }
16867
16868 tng_function_status DECLSPECDLLEXPORT tng_util_force_read_range
16869                 (tng_trajectory_t tng_data,
16870                  const int64_t first_frame,
16871                  const int64_t last_frame,
16872                  float **forces,
16873                  int64_t *stride_length)
16874 {
16875     int64_t n_particles, n_values_per_frame;
16876     char type;
16877     tng_function_status stat;
16878
16879     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16880     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
16881     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
16882     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
16883
16884     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_FORCES,
16885                                                  first_frame, last_frame,
16886                                                  TNG_USE_HASH,
16887                                                  (void **)forces,
16888                                                  &n_particles,
16889                                                  stride_length,
16890                                                  &n_values_per_frame,
16891                                                  &type);
16892
16893     return(stat);
16894 }
16895
16896 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read_range
16897                 (tng_trajectory_t tng_data,
16898                  const int64_t first_frame,
16899                  const int64_t last_frame,
16900                  float **box_shape,
16901                  int64_t *stride_length)
16902 {
16903     int64_t n_values_per_frame;
16904     char type;
16905     tng_function_status stat;
16906
16907     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16908     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
16909     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
16910     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
16911
16912     stat = tng_data_vector_interval_get(tng_data, TNG_TRAJ_BOX_SHAPE,
16913                                         first_frame, last_frame,
16914                                         TNG_USE_HASH,
16915                                         (void **)box_shape,
16916                                         stride_length,
16917                                         &n_values_per_frame,
16918                                         &type);
16919
16920     return(stat);
16921 }
16922
16923 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_set
16924                 (tng_trajectory_t tng_data,
16925                  const int64_t i,
16926                  const int64_t n_values_per_frame,
16927                  const int64_t block_id,
16928                  const char *block_name,
16929                  const char particle_dependency,
16930                  const char compression)
16931 {
16932     tng_trajectory_frame_set_t frame_set;
16933     tng_particle_data_t p_data;
16934     tng_non_particle_data_t np_data;
16935     int64_t n_particles, n_frames;
16936     tng_function_status stat;
16937
16938     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16939     TNG_ASSERT(i >= 0, "TNG library: i (writing interval) must be >= 0.");
16940
16941     if(i <= 0)
16942     {
16943         fprintf(stderr, "TNG library: Cannot set writing frequency to %"PRId64". %s: %d\n",
16944                i, __FILE__, __LINE__);
16945         return(TNG_FAILURE);
16946     }
16947
16948     frame_set = &tng_data->current_trajectory_frame_set;
16949
16950     if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
16951     {
16952         n_frames = tng_data->frame_set_n_frames;
16953
16954         stat = tng_frame_set_new(tng_data, 0, n_frames);
16955         if(stat != TNG_SUCCESS)
16956         {
16957             fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
16958                 __LINE__);
16959             return(stat);
16960         }
16961     }
16962     else
16963     {
16964         n_frames = frame_set->n_frames;
16965     }
16966
16967     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
16968     {
16969         tng_num_particles_get(tng_data, &n_particles);
16970         if(n_particles <= 0)
16971         {
16972             return(TNG_FAILURE);
16973         }
16974
16975         if(tng_particle_data_find(tng_data, block_id, &p_data)
16976         != TNG_SUCCESS)
16977         {
16978             stat = tng_particle_data_block_add(tng_data, block_id,
16979                                                block_name,
16980                                                TNG_FLOAT_DATA,
16981                                                TNG_TRAJECTORY_BLOCK,
16982                                                n_frames, n_values_per_frame, i,
16983                                                0, n_particles,
16984                                                compression, 0);
16985             if(stat != TNG_SUCCESS)
16986             {
16987                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16988                        __FILE__, __LINE__);
16989                 return(stat);
16990             }
16991             p_data = &frame_set->tr_particle_data[frame_set->
16992                                                   n_particle_data_blocks - 1];
16993             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
16994                                                   i, n_particles,
16995                                                   n_values_per_frame);
16996             if(stat != TNG_SUCCESS)
16997             {
16998                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16999                        __FILE__, __LINE__);
17000                 return(stat);
17001             }
17002         }
17003         else
17004         {
17005             if(p_data->stride_length != i)
17006             {
17007                 p_data->stride_length = i;
17008                 stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
17009                                                       i, n_particles,
17010                                                       n_values_per_frame);
17011                 if(stat != TNG_SUCCESS)
17012                 {
17013                     fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17014                            __FILE__, __LINE__);
17015                     return(stat);
17016                 }
17017             }
17018         }
17019     }
17020     else
17021     {
17022         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
17023         {
17024             stat = tng_data_block_add(tng_data, block_id, block_name,
17025                                       TNG_FLOAT_DATA, TNG_TRAJECTORY_BLOCK,
17026                                       n_frames, n_values_per_frame,
17027                                       i, compression, 0);
17028             if(stat != TNG_SUCCESS)
17029             {
17030                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17031                        __FILE__, __LINE__);
17032                 return(stat);
17033             }
17034             np_data = &frame_set->tr_data[frame_set->
17035                                           n_data_blocks - 1];
17036             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
17037                                          i, n_values_per_frame);
17038             if(stat != TNG_SUCCESS)
17039             {
17040                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17041                        __FILE__, __LINE__);
17042                 return(stat);
17043             }
17044         }
17045         else
17046         {
17047             if(np_data->stride_length != i)
17048             {
17049                 np_data->stride_length = i;
17050                 stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
17051                                              i, n_values_per_frame);
17052                 if(stat != TNG_SUCCESS)
17053                 {
17054                     fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17055                            __FILE__, __LINE__);
17056                     return(stat);
17057                 }
17058             }
17059         }
17060     }
17061
17062     return(TNG_SUCCESS);
17063 }
17064
17065 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_double_set
17066                 (tng_trajectory_t tng_data,
17067                  const int64_t i,
17068                  const int64_t n_values_per_frame,
17069                  const int64_t block_id,
17070                  const char *block_name,
17071                  const char particle_dependency,
17072                  const char compression)
17073 {
17074     tng_trajectory_frame_set_t frame_set;
17075     tng_particle_data_t p_data;
17076     tng_non_particle_data_t np_data;
17077     int64_t n_particles, n_frames;
17078     tng_function_status stat;
17079
17080     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17081     TNG_ASSERT(i >= 0, "TNG library: i (writing interval) must be >= 0.");
17082
17083     if(i <= 0)
17084     {
17085         fprintf(stderr, "TNG library: Cannot set writing frequency to %"PRId64". %s: %d\n",
17086                i, __FILE__, __LINE__);
17087         return(TNG_FAILURE);
17088     }
17089
17090     frame_set = &tng_data->current_trajectory_frame_set;
17091
17092     if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
17093     {
17094         n_frames = tng_data->frame_set_n_frames;
17095
17096         stat = tng_frame_set_new(tng_data, 0, n_frames);
17097         if(stat != TNG_SUCCESS)
17098         {
17099             fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
17100                 __LINE__);
17101             return(stat);
17102         }
17103     }
17104     else
17105     {
17106         n_frames = frame_set->n_frames;
17107     }
17108
17109     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
17110     {
17111         tng_num_particles_get(tng_data, &n_particles);
17112
17113         if(n_particles <= 0)
17114         {
17115             return(TNG_FAILURE);
17116         }
17117
17118         if(tng_particle_data_find(tng_data, block_id, &p_data)
17119         != TNG_SUCCESS)
17120         {
17121             stat = tng_particle_data_block_add(tng_data, block_id,
17122                                             block_name,
17123                                             TNG_DOUBLE_DATA,
17124                                             TNG_TRAJECTORY_BLOCK,
17125                                             n_frames, n_values_per_frame, i,
17126                                             0, n_particles,
17127                                             compression, 0);
17128             if(stat != TNG_SUCCESS)
17129             {
17130                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17131                        __FILE__, __LINE__);
17132                 return(stat);
17133             }
17134             p_data = &frame_set->tr_particle_data[frame_set->
17135                                                   n_particle_data_blocks - 1];
17136             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
17137                                                   i, n_particles,
17138                                                   n_values_per_frame);
17139             if(stat != TNG_SUCCESS)
17140             {
17141                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17142                        __FILE__, __LINE__);
17143                 return(stat);
17144             }
17145         }
17146         else
17147         {
17148             p_data->stride_length = i;
17149         }
17150     }
17151     else
17152     {
17153         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
17154         {
17155             stat = tng_data_block_add(tng_data, block_id, block_name,
17156                                       TNG_DOUBLE_DATA, TNG_TRAJECTORY_BLOCK,
17157                                       n_frames, n_values_per_frame,
17158                                       i, compression, 0);
17159             if(stat != TNG_SUCCESS)
17160             {
17161                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17162                        __FILE__, __LINE__);
17163                 return(stat);
17164             }
17165             np_data = &frame_set->tr_data[frame_set->
17166                                           n_data_blocks - 1];
17167             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
17168                                          i, n_values_per_frame);
17169             if(stat != TNG_SUCCESS)
17170             {
17171                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17172                        __FILE__, __LINE__);
17173                 return(stat);
17174             }
17175         }
17176         else
17177         {
17178             np_data->stride_length = i;
17179         }
17180     }
17181
17182     return(TNG_SUCCESS);
17183 }
17184
17185 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_frequency_set
17186                 (tng_trajectory_t tng_data,
17187                  const int64_t i,
17188                  const int64_t n_values_per_frame,
17189                  const int64_t block_id,
17190                  const char *block_name,
17191                  const char particle_dependency,
17192                  const char compression)
17193 {
17194     fprintf(stderr, "TNG library: Using obsolete function tng_util_generic_write_frequency_set(). "
17195            "See documentation. %s: %d", __FILE__, __LINE__);
17196     return(tng_util_generic_write_interval_set(tng_data, i, n_values_per_frame,
17197                                                block_id, block_name,
17198                                                particle_dependency,
17199                                                compression));
17200 }
17201 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_set
17202                 (tng_trajectory_t tng_data,
17203                  const int64_t i)
17204 {
17205     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17206     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
17207
17208     return(tng_util_generic_write_interval_set(tng_data, i, 3,
17209                                                TNG_TRAJ_POSITIONS,
17210                                                "POSITIONS",
17211                                                TNG_PARTICLE_BLOCK_DATA,
17212                                                TNG_TNG_COMPRESSION));
17213 }
17214
17215 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_double_set
17216                 (tng_trajectory_t tng_data,
17217                  const int64_t i)
17218 {
17219     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17220     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
17221
17222     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
17223                                                       TNG_TRAJ_POSITIONS,
17224                                                       "POSITIONS",
17225                                                       TNG_PARTICLE_BLOCK_DATA,
17226                                                       TNG_TNG_COMPRESSION));
17227 }
17228
17229 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_frequency_set
17230                 (tng_trajectory_t tng_data,
17231                  const int64_t i)
17232 {
17233     fprintf(stderr, "TNG library: Using obsolete function tng_util_pos_write_frequency_set(). "
17234            "See documentation. %s: %d", __FILE__, __LINE__);
17235     return(tng_util_pos_write_interval_set(tng_data, i));
17236 }
17237
17238 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_set
17239                 (tng_trajectory_t tng_data,
17240                  const int64_t i)
17241 {
17242     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17243     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
17244
17245     return(tng_util_generic_write_interval_set(tng_data, i, 3,
17246                                                TNG_TRAJ_VELOCITIES,
17247                                                "VELOCITIES",
17248                                                TNG_PARTICLE_BLOCK_DATA,
17249                                                TNG_TNG_COMPRESSION));
17250 }
17251
17252 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_double_set
17253                 (tng_trajectory_t tng_data,
17254                  const int64_t i)
17255 {
17256     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17257     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
17258
17259     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
17260                                                       TNG_TRAJ_VELOCITIES,
17261                                                       "VELOCITIES",
17262                                                       TNG_PARTICLE_BLOCK_DATA,
17263                                                       TNG_TNG_COMPRESSION));
17264 }
17265
17266 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_frequency_set
17267                 (tng_trajectory_t tng_data,
17268                  const int64_t i)
17269 {
17270     fprintf(stderr, "TNG library: Using obsolete function tng_util_vel_write_frequency_set(). "
17271            "See documentation. %s: %d", __FILE__, __LINE__);
17272     return(tng_util_vel_write_interval_set(tng_data, i));
17273 }
17274
17275 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_set
17276                 (tng_trajectory_t tng_data,
17277                  const int64_t i)
17278 {
17279     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17280     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
17281
17282     return(tng_util_generic_write_interval_set(tng_data, i, 3,
17283                                                TNG_TRAJ_FORCES,
17284                                                "FORCES",
17285                                                TNG_PARTICLE_BLOCK_DATA,
17286                                                TNG_GZIP_COMPRESSION));
17287 }
17288
17289 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_double_set
17290                 (tng_trajectory_t tng_data,
17291                  const int64_t i)
17292 {
17293     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17294     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
17295
17296     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
17297                                                       TNG_TRAJ_FORCES,
17298                                                       "FORCES",
17299                                                       TNG_PARTICLE_BLOCK_DATA,
17300                                                       TNG_GZIP_COMPRESSION));
17301 }
17302
17303 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_frequency_set
17304                 (tng_trajectory_t tng_data,
17305                  const int64_t i)
17306 {
17307     fprintf(stderr, "TNG library: Using obsolete function tng_util_force_write_frequency_set(). "
17308            "See documentation. %s: %d", __FILE__, __LINE__);
17309     return(tng_util_force_write_interval_set(tng_data, i));
17310 }
17311
17312 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_set
17313                 (tng_trajectory_t tng_data,
17314                  const int64_t i)
17315 {
17316     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17317     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
17318
17319     return(tng_util_generic_write_interval_set(tng_data, i, 9,
17320                                                TNG_TRAJ_BOX_SHAPE,
17321                                                "BOX SHAPE",
17322                                                TNG_NON_PARTICLE_BLOCK_DATA,
17323                                                TNG_GZIP_COMPRESSION));
17324 }
17325
17326 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_double_set
17327                 (tng_trajectory_t tng_data,
17328                  const int64_t i)
17329 {
17330     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17331     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
17332
17333     return(tng_util_generic_write_interval_double_set(tng_data, i, 9,
17334                                                       TNG_TRAJ_BOX_SHAPE,
17335                                                       "BOX SHAPE",
17336                                                       TNG_NON_PARTICLE_BLOCK_DATA,
17337                                                       TNG_GZIP_COMPRESSION));
17338 }
17339
17340 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_frequency_set
17341                 (tng_trajectory_t tng_data,
17342                  const int64_t i)
17343 {
17344     fprintf(stderr, "TNG library: Using obsolete function tng_util_box_shape_write_frequency_set(). "
17345            "See documentation. %s: %d", __FILE__, __LINE__);
17346     return(tng_util_box_shape_write_interval_set(tng_data, i));
17347 }
17348
17349 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write
17350                 (tng_trajectory_t tng_data,
17351                  const int64_t frame_nr,
17352                  const float *values,
17353                  const int64_t n_values_per_frame,
17354                  const int64_t block_id,
17355                  const char *block_name,
17356                  const char particle_dependency,
17357                  const char compression)
17358 {
17359     tng_trajectory_frame_set_t frame_set;
17360     tng_particle_data_t p_data;
17361     tng_non_particle_data_t np_data;
17362     int64_t n_particles = 0, n_frames, stride_length = 100, frame_pos;
17363     int64_t last_frame;
17364     int is_first_frame_flag = 0;
17365     char block_type_flag;
17366     tng_function_status stat;
17367
17368     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17369     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17370     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
17371
17372     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
17373     {
17374         tng_num_particles_get(tng_data, &n_particles);
17375         TNG_ASSERT(n_particles > 0, "TNG library: There must be particles in the system to write particle data.");
17376     }
17377
17378     if(values == 0)
17379     {
17380         return(TNG_FAILURE);
17381     }
17382
17383     frame_set = &tng_data->current_trajectory_frame_set;
17384
17385     if(frame_nr < 0)
17386     {
17387         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
17388         n_frames = stride_length = 1;
17389     }
17390     else
17391     {
17392         block_type_flag = TNG_TRAJECTORY_BLOCK;
17393
17394         if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
17395         {
17396             stat = tng_frame_set_new(tng_data, 0, tng_data->frame_set_n_frames);
17397             if(stat != TNG_SUCCESS)
17398             {
17399                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
17400                     __LINE__);
17401                 return(stat);
17402             }
17403         }
17404         last_frame = frame_set->first_frame +
17405                      frame_set->n_frames - 1;
17406         if(frame_nr > last_frame)
17407         {
17408             stat = tng_frame_set_write(tng_data, TNG_USE_HASH);
17409             if(stat != TNG_SUCCESS)
17410             {
17411                 fprintf(stderr, "TNG library: Cannot write frame set.  %s: %d\n", __FILE__,
17412                     __LINE__);
17413                 return(stat);
17414             }
17415             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
17416             {
17417                 last_frame = frame_nr - 1;
17418             }
17419             stat = tng_frame_set_new(tng_data, last_frame + 1,
17420                                      tng_data->frame_set_n_frames);
17421             if(stat != TNG_SUCCESS)
17422             {
17423                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
17424                     __LINE__);
17425                 return(stat);
17426             }
17427         }
17428         if(frame_set->n_unwritten_frames == 0)
17429         {
17430             is_first_frame_flag = 1;
17431         }
17432         frame_set->n_unwritten_frames = frame_nr -
17433                                         frame_set->first_frame + 1;
17434
17435         n_frames = frame_set->n_frames;
17436     }
17437
17438     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
17439     {
17440         if(tng_particle_data_find(tng_data, block_id, &p_data)
17441         != TNG_SUCCESS)
17442         {
17443             stat = tng_particle_data_block_add(tng_data, block_id,
17444                                                block_name,
17445                                                TNG_FLOAT_DATA,
17446                                                block_type_flag,
17447                                                n_frames, n_values_per_frame,
17448                                                stride_length,
17449                                                0, n_particles,
17450                                                compression, 0);
17451             if(stat != TNG_SUCCESS)
17452             {
17453                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17454                        __FILE__, __LINE__);
17455                 return(stat);
17456             }
17457             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
17458             {
17459                 p_data = &frame_set->tr_particle_data[frame_set->
17460                                                     n_particle_data_blocks - 1];
17461             }
17462             else
17463             {
17464                 p_data = &tng_data->non_tr_particle_data[tng_data->
17465                                                     n_particle_data_blocks - 1];
17466             }
17467             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
17468                                                   stride_length, n_particles,
17469                                                   n_values_per_frame);
17470             if(stat != TNG_SUCCESS)
17471             {
17472                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17473                        __FILE__, __LINE__);
17474                 return(stat);
17475             }
17476         }
17477
17478         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
17479         {
17480             stride_length = p_data->stride_length;
17481
17482             if(is_first_frame_flag || p_data->first_frame_with_data < frame_set->first_frame)
17483             {
17484                 p_data->first_frame_with_data = frame_nr;
17485                 frame_pos = 0;
17486             }
17487             else
17488             {
17489                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
17490             }
17491
17492             memcpy((char *)p_data->values + sizeof(float) * frame_pos * n_particles *
17493                    n_values_per_frame, values, sizeof(float) *
17494                    n_particles * n_values_per_frame);
17495         }
17496         else
17497         {
17498             memcpy(p_data->values, values, sizeof(float) * n_particles *
17499                    n_values_per_frame);
17500         }
17501     }
17502     else
17503     {
17504         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
17505         {
17506             stat = tng_data_block_add(tng_data, block_id, block_name,
17507                                       TNG_FLOAT_DATA, block_type_flag,
17508                                       n_frames, n_values_per_frame,
17509                                       stride_length, compression, 0);
17510             if(stat != TNG_SUCCESS)
17511             {
17512                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17513                        __FILE__, __LINE__);
17514                 return(stat);
17515             }
17516             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
17517             {
17518                 np_data = &frame_set->tr_data[frame_set->
17519                                               n_data_blocks - 1];
17520             }
17521             else
17522             {
17523                 np_data = &tng_data->non_tr_data[tng_data->
17524                                                  n_data_blocks - 1];
17525             }
17526             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
17527                                          stride_length, n_values_per_frame);
17528             if(stat != TNG_SUCCESS)
17529             {
17530                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17531                        __FILE__, __LINE__);
17532                 return(stat);
17533             }
17534         }
17535
17536         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
17537         {
17538             stride_length = np_data->stride_length;
17539
17540             if(is_first_frame_flag || np_data->first_frame_with_data < frame_set->first_frame)
17541             {
17542                 np_data->first_frame_with_data = frame_nr;
17543                 frame_pos = 0;
17544             }
17545             else
17546             {
17547                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
17548             }
17549
17550             memcpy((char *)np_data->values + sizeof(float) * frame_pos *
17551                    n_values_per_frame, values, sizeof(float) *
17552                    n_values_per_frame);
17553         }
17554         else
17555         {
17556             memcpy(np_data->values, values, sizeof(float) * n_values_per_frame);
17557         }
17558     }
17559
17560     return(TNG_SUCCESS);
17561 }
17562
17563 tng_function_status DECLSPECDLLEXPORT tng_util_generic_double_write
17564                 (tng_trajectory_t tng_data,
17565                  const int64_t frame_nr,
17566                  const double *values,
17567                  const int64_t n_values_per_frame,
17568                  const int64_t block_id,
17569                  const char *block_name,
17570                  const char particle_dependency,
17571                  const char compression)
17572 {
17573     tng_trajectory_frame_set_t frame_set;
17574     tng_particle_data_t p_data;
17575     tng_non_particle_data_t np_data;
17576     int64_t n_particles = 0, n_frames, stride_length = 100, frame_pos;
17577     int64_t last_frame;
17578     int is_first_frame_flag = 0;
17579     char block_type_flag;
17580     tng_function_status stat;
17581
17582     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17583     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17584     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
17585
17586     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
17587     {
17588         tng_num_particles_get(tng_data, &n_particles);
17589         TNG_ASSERT(n_particles > 0, "TNG library: There must be particles in the system to write particle data.");
17590     }
17591
17592     if(values == 0)
17593     {
17594         return(TNG_FAILURE);
17595     }
17596
17597     frame_set = &tng_data->current_trajectory_frame_set;
17598
17599     if(frame_nr < 0)
17600     {
17601         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
17602         n_frames = stride_length = 1;
17603     }
17604     else
17605     {
17606         block_type_flag = TNG_TRAJECTORY_BLOCK;
17607
17608         n_frames = tng_data->frame_set_n_frames;
17609
17610         if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
17611         {
17612             stat = tng_frame_set_new(tng_data, 0, n_frames);
17613             if(stat != TNG_SUCCESS)
17614             {
17615                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
17616                     __LINE__);
17617                 return(stat);
17618             }
17619         }
17620         else
17621         {
17622             n_frames = frame_set->n_frames;
17623         }
17624         last_frame = frame_set->first_frame +
17625                      frame_set->n_frames - 1;
17626         if(frame_nr > last_frame)
17627         {
17628             stat = tng_frame_set_write(tng_data, TNG_USE_HASH);
17629             if(stat != TNG_SUCCESS)
17630             {
17631                 fprintf(stderr, "TNG library: Cannot write frame set.  %s: %d\n", __FILE__,
17632                     __LINE__);
17633                 return(stat);
17634             }
17635             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
17636             {
17637                 last_frame = frame_nr - 1;
17638             }
17639             stat = tng_frame_set_new(tng_data, last_frame + 1, n_frames);
17640             if(stat != TNG_SUCCESS)
17641             {
17642                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
17643                     __LINE__);
17644                 return(stat);
17645             }
17646         }
17647         if(frame_set->n_unwritten_frames == 0)
17648         {
17649             is_first_frame_flag = 1;
17650         }
17651         frame_set->n_unwritten_frames = frame_nr -
17652                                         frame_set->first_frame + 1;
17653     }
17654
17655     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
17656     {
17657         if(tng_particle_data_find(tng_data, block_id, &p_data)
17658         != TNG_SUCCESS)
17659         {
17660             stat = tng_particle_data_block_add(tng_data, block_id,
17661                                             block_name,
17662                                             TNG_DOUBLE_DATA,
17663                                             block_type_flag,
17664                                             n_frames, n_values_per_frame,
17665                                             stride_length,
17666                                             0, n_particles,
17667                                             compression, 0);
17668             if(stat != TNG_SUCCESS)
17669             {
17670                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17671                        __FILE__, __LINE__);
17672                 return(stat);
17673             }
17674             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
17675             {
17676                 p_data = &frame_set->tr_particle_data[frame_set->
17677                                                     n_particle_data_blocks - 1];
17678             }
17679             else
17680             {
17681                 p_data = &tng_data->non_tr_particle_data[tng_data->
17682                                                     n_particle_data_blocks - 1];
17683             }
17684             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
17685                                                   stride_length, n_particles,
17686                                                   n_values_per_frame);
17687             if(stat != TNG_SUCCESS)
17688             {
17689                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17690                        __FILE__, __LINE__);
17691                 return(stat);
17692             }
17693         }
17694
17695         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
17696         {
17697             stride_length = p_data->stride_length;
17698
17699             if(is_first_frame_flag)
17700             {
17701                 p_data->first_frame_with_data = frame_nr;
17702                 frame_pos = 0;
17703             }
17704             else
17705             {
17706                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
17707             }
17708
17709             memcpy((char *)p_data->values + sizeof(double) * frame_pos * n_particles *
17710                    n_values_per_frame, values, sizeof(double) *
17711                    n_particles * n_values_per_frame);
17712         }
17713         else
17714         {
17715             memcpy(p_data->values, values, sizeof(double) * n_particles *
17716                    n_values_per_frame);
17717         }
17718     }
17719     else
17720     {
17721         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
17722         {
17723             stat = tng_data_block_add(tng_data, block_id, block_name,
17724                                       TNG_DOUBLE_DATA, block_type_flag,
17725                                       n_frames, n_values_per_frame,
17726                                       stride_length, compression, 0);
17727             if(stat != TNG_SUCCESS)
17728             {
17729                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17730                        __FILE__, __LINE__);
17731                 return(stat);
17732             }
17733             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
17734             {
17735                 np_data = &frame_set->tr_data[frame_set->
17736                                               n_data_blocks - 1];
17737             }
17738             else
17739             {
17740                 np_data = &tng_data->non_tr_data[tng_data->
17741                                                  n_data_blocks - 1];
17742             }
17743             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
17744                                          stride_length, n_values_per_frame);
17745             if(stat != TNG_SUCCESS)
17746             {
17747                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17748                        __FILE__, __LINE__);
17749                 return(stat);
17750             }
17751         }
17752
17753         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
17754         {
17755             stride_length = np_data->stride_length;
17756
17757             if(is_first_frame_flag)
17758             {
17759                 np_data->first_frame_with_data = frame_nr;
17760                 frame_pos = 0;
17761             }
17762             else
17763             {
17764                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
17765             }
17766
17767             memcpy((char *)np_data->values + sizeof(double) * frame_pos *
17768                    n_values_per_frame, values, sizeof(double) *
17769                    n_values_per_frame);
17770         }
17771         else
17772         {
17773             memcpy(np_data->values, values, sizeof(double) * n_values_per_frame);
17774         }
17775     }
17776
17777     return(TNG_SUCCESS);
17778 }
17779
17780 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write
17781                 (tng_trajectory_t tng_data,
17782                  const int64_t frame_nr,
17783                  const float *positions)
17784 {
17785     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17786     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17787     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
17788
17789     return(tng_util_generic_write(tng_data, frame_nr, positions, 3,
17790                                   TNG_TRAJ_POSITIONS, "POSITIONS",
17791                                   TNG_PARTICLE_BLOCK_DATA,
17792                                   TNG_TNG_COMPRESSION));
17793 }
17794
17795 tng_function_status DECLSPECDLLEXPORT tng_util_pos_double_write
17796                 (tng_trajectory_t tng_data,
17797                  const int64_t frame_nr,
17798                  const double *positions)
17799 {
17800     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17801     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17802     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
17803
17804     return(tng_util_generic_double_write(tng_data, frame_nr, positions, 3,
17805                                          TNG_TRAJ_POSITIONS, "POSITIONS",
17806                                          TNG_PARTICLE_BLOCK_DATA,
17807                                          TNG_TNG_COMPRESSION));
17808 }
17809
17810 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write
17811                 (tng_trajectory_t tng_data,
17812                  const int64_t frame_nr,
17813                  const float *velocities)
17814 {
17815     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17816     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17817     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
17818
17819     return(tng_util_generic_write(tng_data, frame_nr, velocities, 3,
17820                                   TNG_TRAJ_VELOCITIES, "VELOCITIES",
17821                                   TNG_PARTICLE_BLOCK_DATA,
17822                                   TNG_TNG_COMPRESSION));
17823 }
17824
17825 tng_function_status DECLSPECDLLEXPORT tng_util_vel_double_write
17826                 (tng_trajectory_t tng_data,
17827                  const int64_t frame_nr,
17828                  const double *velocities)
17829 {
17830     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17831     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17832     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
17833
17834     return(tng_util_generic_double_write(tng_data, frame_nr, velocities, 3,
17835                                          TNG_TRAJ_VELOCITIES, "VELOCITIES",
17836                                          TNG_PARTICLE_BLOCK_DATA,
17837                                          TNG_TNG_COMPRESSION));
17838 }
17839
17840 tng_function_status DECLSPECDLLEXPORT tng_util_force_write
17841                 (tng_trajectory_t tng_data,
17842                  const int64_t frame_nr,
17843                  const float *forces)
17844 {
17845     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17846     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17847     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17848
17849     return(tng_util_generic_write(tng_data, frame_nr, forces, 3,
17850                                   TNG_TRAJ_FORCES, "FORCES",
17851                                   TNG_PARTICLE_BLOCK_DATA,
17852                                   TNG_GZIP_COMPRESSION));
17853 }
17854
17855 tng_function_status DECLSPECDLLEXPORT tng_util_force_double_write
17856                 (tng_trajectory_t tng_data,
17857                  const int64_t frame_nr,
17858                  const double *forces)
17859 {
17860     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17861     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17862     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17863
17864     return(tng_util_generic_double_write(tng_data, frame_nr, forces, 3,
17865                                          TNG_TRAJ_FORCES, "FORCES",
17866                                          TNG_PARTICLE_BLOCK_DATA,
17867                                          TNG_GZIP_COMPRESSION));
17868 }
17869
17870 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write
17871                 (tng_trajectory_t tng_data,
17872                  const int64_t frame_nr,
17873                  const float *box_shape)
17874 {
17875     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17876     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17877     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17878
17879     return(tng_util_generic_write(tng_data, frame_nr, box_shape, 9,
17880                                   TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
17881                                   TNG_NON_PARTICLE_BLOCK_DATA,
17882                                   TNG_GZIP_COMPRESSION));
17883 }
17884
17885 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_double_write
17886                 (tng_trajectory_t tng_data,
17887                  const int64_t frame_nr,
17888                  const double *box_shape)
17889 {
17890     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17891     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17892     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17893
17894     return(tng_util_generic_double_write(tng_data, frame_nr, box_shape, 9,
17895                                          TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
17896                                          TNG_NON_PARTICLE_BLOCK_DATA,
17897                                          TNG_GZIP_COMPRESSION));
17898 }
17899
17900 tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_write
17901                 (tng_trajectory_t tng_data,
17902                  const int64_t frame_nr,
17903                  const double time,
17904                  const float *values,
17905                  const int64_t n_values_per_frame,
17906                  const int64_t block_id,
17907                  const char *block_name,
17908                  const char particle_dependency,
17909                  const char compression)
17910 {
17911     tng_trajectory_frame_set_t frame_set;
17912     tng_function_status stat;
17913
17914     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17915     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17916     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17917     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
17918
17919     stat = tng_util_generic_write(tng_data, frame_nr, values, n_values_per_frame,
17920                                   block_id, block_name,
17921                                   particle_dependency,
17922                                   compression);
17923
17924     if(stat != TNG_SUCCESS)
17925     {
17926         return(stat);
17927     }
17928
17929     frame_set = &tng_data->current_trajectory_frame_set;
17930
17931     /* first_frame_time is -1 when it is not yet set. */
17932     if(frame_set->first_frame_time < -0.1)
17933     {
17934         if(frame_nr > frame_set->first_frame)
17935         {
17936             stat = tng_frame_set_first_frame_time_set(tng_data,
17937                                                       time -
17938                                                       (frame_nr -
17939                                                        frame_set->first_frame) *
17940                                                       tng_data->time_per_frame);
17941         }
17942         else
17943         {
17944             stat = tng_frame_set_first_frame_time_set(tng_data, time);
17945         }
17946     }
17947     return(stat);
17948 }
17949
17950 tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_double_write
17951                 (tng_trajectory_t tng_data,
17952                  const int64_t frame_nr,
17953                  const double time,
17954                  const double *values,
17955                  const int64_t n_values_per_frame,
17956                  const int64_t block_id,
17957                  const char *block_name,
17958                  const char particle_dependency,
17959                  const char compression)
17960 {
17961     tng_trajectory_frame_set_t frame_set;
17962     tng_function_status stat;
17963
17964     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17965     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17966     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17967     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
17968
17969     stat = tng_util_generic_double_write(tng_data, frame_nr, values, n_values_per_frame,
17970                                          block_id, block_name,
17971                                          particle_dependency,
17972                                          compression);
17973
17974     if(stat != TNG_SUCCESS)
17975     {
17976         return(stat);
17977     }
17978
17979     frame_set = &tng_data->current_trajectory_frame_set;
17980
17981     /* first_frame_time is -1 when it is not yet set. */
17982     if(frame_set->first_frame_time < -0.1)
17983     {
17984         if(frame_nr > frame_set->first_frame)
17985         {
17986             stat = tng_frame_set_first_frame_time_set(tng_data,
17987                                                       time -
17988                                                       (frame_nr -
17989                                                        frame_set->first_frame) *
17990                                                       tng_data->time_per_frame);
17991         }
17992         else
17993         {
17994             stat = tng_frame_set_first_frame_time_set(tng_data, time);
17995         }
17996     }
17997     return(stat);
17998 }
17999
18000 tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_write
18001                 (tng_trajectory_t tng_data,
18002                  const int64_t frame_nr,
18003                  const double time,
18004                  const float *positions)
18005 {
18006     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18007     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18008     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18009     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
18010
18011     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, positions,
18012                                             3, TNG_TRAJ_POSITIONS, "POSITIONS",
18013                                             TNG_PARTICLE_BLOCK_DATA,
18014                                             TNG_TNG_COMPRESSION));
18015 }
18016
18017 tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_double_write
18018                 (tng_trajectory_t tng_data,
18019                  const int64_t frame_nr,
18020                  const double time,
18021                  const double *positions)
18022 {
18023     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18024     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18025     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18026     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
18027
18028     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
18029                                                    positions, 3,
18030                                                    TNG_TRAJ_POSITIONS,
18031                                                    "POSITIONS",
18032                                                    TNG_PARTICLE_BLOCK_DATA,
18033                                                    TNG_TNG_COMPRESSION));
18034 }
18035
18036 tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_write
18037                 (tng_trajectory_t tng_data,
18038                  const int64_t frame_nr,
18039                  const double time,
18040                  const float *velocities)
18041 {
18042     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18043     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18044     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18045     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
18046
18047     return(tng_util_generic_with_time_write(tng_data, frame_nr, time,
18048                                             velocities, 3,
18049                                             TNG_TRAJ_VELOCITIES,
18050                                             "VELOCITIES",
18051                                             TNG_PARTICLE_BLOCK_DATA,
18052                                             TNG_TNG_COMPRESSION));
18053 }
18054
18055 tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_double_write
18056                 (tng_trajectory_t tng_data,
18057                  const int64_t frame_nr,
18058                  const double time,
18059                  const double *velocities)
18060 {
18061     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18062     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18063     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18064     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
18065
18066     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
18067                                                    velocities, 3,
18068                                                    TNG_TRAJ_VELOCITIES,
18069                                                    "VELOCITIES",
18070                                                    TNG_PARTICLE_BLOCK_DATA,
18071                                                    TNG_TNG_COMPRESSION));
18072 }
18073
18074 tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_write
18075                 (tng_trajectory_t tng_data,
18076                  const int64_t frame_nr,
18077                  const double time,
18078                  const float *forces)
18079 {
18080     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18081     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18082     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18083     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
18084
18085     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, forces,
18086                                             3, TNG_TRAJ_FORCES, "FORCES",
18087                                             TNG_PARTICLE_BLOCK_DATA,
18088                                             TNG_GZIP_COMPRESSION));
18089 }
18090
18091 tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_double_write
18092                 (tng_trajectory_t tng_data,
18093                  const int64_t frame_nr,
18094                  const double time,
18095                  const double *forces)
18096 {
18097     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18098     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18099     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18100     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
18101
18102     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
18103                                                    forces, 3,
18104                                                    TNG_TRAJ_FORCES, "FORCES",
18105                                                    TNG_PARTICLE_BLOCK_DATA,
18106                                                    TNG_GZIP_COMPRESSION));
18107 }
18108
18109 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_write
18110                 (tng_trajectory_t tng_data,
18111                  const int64_t frame_nr,
18112                  const double time,
18113                  const float *box_shape)
18114 {
18115     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18116     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18117     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18118     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
18119
18120     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, box_shape,
18121                                             9, TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
18122                                             TNG_NON_PARTICLE_BLOCK_DATA,
18123                                             TNG_GZIP_COMPRESSION));
18124 }
18125
18126 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_double_write
18127                 (tng_trajectory_t tng_data,
18128                  const int64_t frame_nr,
18129                  const double time,
18130                  const double *box_shape)
18131 {
18132     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18133     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18134     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18135     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
18136
18137     return(tng_util_generic_with_time_double_write(tng_data, frame_nr,
18138                                                    time, box_shape, 9,
18139                                                    TNG_TRAJ_BOX_SHAPE,
18140                                                    "BOX SHAPE",
18141                                                    TNG_NON_PARTICLE_BLOCK_DATA,
18142                                                    TNG_GZIP_COMPRESSION));
18143 }
18144
18145 tng_function_status DECLSPECDLLEXPORT tng_util_frame_current_compression_get
18146                 (tng_trajectory_t tng_data,
18147                  const int64_t block_id,
18148                  int64_t *codec_id,
18149                  float *factor)
18150 {
18151     tng_trajectory_frame_set_t frame_set;
18152     tng_particle_data_t p_data = 0;
18153     tng_non_particle_data_t np_data = 0;
18154     tng_function_status stat;
18155     int64_t i;
18156     int block_type = -1;
18157
18158     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18159     TNG_ASSERT(codec_id, "TNG library: The pointer to the returned codec id must not be a NULL pointer.");
18160     TNG_ASSERT(factor, "TNG library: The pointer to the returned multiplication factor must not be a NULL pointer.");
18161
18162     frame_set = &tng_data->current_trajectory_frame_set;
18163
18164     stat = tng_particle_data_find(tng_data, block_id, &p_data);
18165     if(stat == TNG_SUCCESS)
18166     {
18167         block_type = TNG_PARTICLE_BLOCK_DATA;
18168     }
18169     else
18170     {
18171         stat = tng_data_find(tng_data, block_id, &np_data);
18172         if(stat == TNG_SUCCESS)
18173         {
18174             block_type = TNG_NON_PARTICLE_BLOCK_DATA;
18175         }
18176         else
18177         {
18178             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
18179             if(stat != TNG_SUCCESS)
18180             {
18181                 return(stat);
18182             }
18183             stat = tng_particle_data_find(tng_data, block_id, &p_data);
18184             if(stat == TNG_SUCCESS)
18185             {
18186                 block_type = TNG_PARTICLE_BLOCK_DATA;
18187             }
18188             else
18189             {
18190                 stat = tng_data_find(tng_data, block_id, &np_data);
18191                 if(stat == TNG_SUCCESS)
18192                 {
18193                     block_type = TNG_NON_PARTICLE_BLOCK_DATA;
18194                 }
18195                 else
18196                 {
18197                     return(stat);
18198                 }
18199             }
18200         }
18201     }
18202     if(block_type == TNG_PARTICLE_BLOCK_DATA)
18203     {
18204         if(p_data->last_retrieved_frame < 0)
18205         {
18206             i = p_data->first_frame_with_data;
18207         }
18208         else
18209         {
18210             i = p_data->last_retrieved_frame;
18211         }
18212     }
18213     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
18214     {
18215         if(np_data->last_retrieved_frame < 0)
18216         {
18217             i = np_data->first_frame_with_data;
18218         }
18219         else
18220         {
18221             i = np_data->last_retrieved_frame;
18222         }
18223     }
18224     else
18225     {
18226         return(TNG_FAILURE);
18227     }
18228     if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
18229     {
18230         stat = tng_frame_set_of_frame_find(tng_data, i);
18231         if(stat != TNG_SUCCESS)
18232         {
18233             return(stat);
18234         }
18235         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
18236         if(stat != TNG_SUCCESS)
18237         {
18238             fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
18239                 __FILE__, __LINE__);
18240             return(stat);
18241         }
18242     }
18243     if(block_type == TNG_PARTICLE_BLOCK_DATA)
18244     {
18245         *codec_id = p_data->codec_id;
18246         *factor   = (float)p_data->compression_multiplier;
18247     }
18248     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
18249     {
18250         *codec_id = np_data->codec_id;
18251         *factor   = (float)np_data->compression_multiplier;
18252     }
18253     return(TNG_SUCCESS);
18254 }
18255
18256 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_next_frame_present_data_blocks_find
18257                 (tng_trajectory_t tng_data,
18258                  int64_t current_frame,
18259                  const int64_t n_requested_data_block_ids,
18260                  const int64_t *requested_data_block_ids,
18261                  int64_t *next_frame,
18262                  int64_t *n_data_blocks_in_next_frame,
18263                  int64_t **data_block_ids_in_next_frame)
18264 {
18265     tng_trajectory_frame_set_t frame_set;
18266     tng_function_status stat;
18267     tng_particle_data_t p_data;
18268     tng_non_particle_data_t np_data;
18269     tng_gen_block_t block;
18270     int64_t i, j, block_id, *temp;
18271     int64_t data_frame, frame_diff, min_diff;
18272     int64_t size, frame_set_file_pos;
18273     int found, read_all = 0;
18274     long file_pos;
18275
18276     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18277     TNG_ASSERT(next_frame, "TNG library: The pointer to the next frame must not be NULL.");
18278     TNG_ASSERT(n_data_blocks_in_next_frame, "TNG library: The pointer to n_data_blocks_in_next_frame must not be NULL.");
18279     TNG_ASSERT(data_block_ids_in_next_frame, "TNG library: The pointer to the list of data block IDs must not be NULL.");
18280
18281     if(n_requested_data_block_ids)
18282     {
18283         TNG_ASSERT(requested_data_block_ids, "TNG library: If the number of requested data blocks is > 0 then the array of data block IDs must not be NULL.");
18284         size = sizeof(int64_t) * n_requested_data_block_ids;
18285         temp = realloc(*data_block_ids_in_next_frame, size);
18286         if(!temp)
18287         {
18288             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
18289                     sizeof(int64_t) * (*n_data_blocks_in_next_frame),
18290                     __FILE__, __LINE__);
18291             free(*data_block_ids_in_next_frame);
18292             *data_block_ids_in_next_frame = 0;
18293             return(TNG_CRITICAL);
18294         }
18295         *data_block_ids_in_next_frame = temp;
18296     }
18297
18298     frame_set = &tng_data->current_trajectory_frame_set;
18299
18300     current_frame += 1;
18301
18302     if(current_frame < frame_set->first_frame ||
18303        current_frame >= frame_set->first_frame + frame_set->n_frames)
18304     {
18305         frame_set_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
18306         stat = tng_frame_set_of_frame_find(tng_data, current_frame);
18307         if(stat != TNG_SUCCESS)
18308         {
18309             /* If the frame set search found the frame set after the starting
18310              * frame set there is a gap in the frame sets. So, even if the frame
18311              * was not found the next frame with data is still in the found
18312              * frame set. */
18313             if(stat == TNG_CRITICAL || frame_set->prev_frame_set_file_pos !=
18314                frame_set_file_pos)
18315             {
18316                 return(stat);
18317             }
18318             current_frame = frame_set->first_frame;
18319         }
18320     }
18321
18322     if(frame_set->n_particle_data_blocks <= 0 || frame_set->n_data_blocks <= 0)
18323     {
18324         tng_block_init(&block);
18325         file_pos = ftell(tng_data->input_file);
18326         /* Read all blocks until next frame set block */
18327         stat = tng_block_header_read(tng_data, block);
18328         while(file_pos < tng_data->input_file_len &&
18329             stat != TNG_CRITICAL &&
18330             block->id != TNG_TRAJECTORY_FRAME_SET)
18331         {
18332             stat = tng_block_read_next(tng_data, block,
18333                                        TNG_USE_HASH);
18334             if(stat != TNG_CRITICAL)
18335             {
18336                 file_pos = ftell(tng_data->input_file);
18337                 if(file_pos < tng_data->input_file_len)
18338                 {
18339                     stat = tng_block_header_read(tng_data, block);
18340                 }
18341             }
18342         }
18343         tng_block_destroy(&block);
18344         if(stat == TNG_CRITICAL)
18345         {
18346             fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
18347                     file_pos, __FILE__, __LINE__);
18348             return(stat);
18349         }
18350         read_all = 1;
18351     }
18352
18353     min_diff = -1;
18354
18355     *n_data_blocks_in_next_frame = 0;
18356
18357     for(i = 0; i < frame_set->n_particle_data_blocks; i++)
18358     {
18359         p_data = &frame_set->tr_particle_data[i];
18360         block_id = p_data->block_id;
18361
18362         if(n_requested_data_block_ids > 0)
18363         {
18364             found = 0;
18365             for(j = 0; j < n_requested_data_block_ids; j++)
18366             {
18367                 if(block_id == requested_data_block_ids[j])
18368                 {
18369                     found = 1;
18370                     break;
18371                 }
18372             }
18373             if(!found)
18374             {
18375                 continue;
18376             }
18377         }
18378
18379         if(!read_all && (p_data->last_retrieved_frame < frame_set->first_frame ||
18380            p_data->last_retrieved_frame >=
18381            frame_set->first_frame + frame_set->n_frames))
18382         {
18383             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data,
18384                                                                       TNG_USE_HASH, block_id);
18385             if(stat == TNG_CRITICAL)
18386             {
18387                 fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
18388                     __FILE__, __LINE__);
18389                 return(stat);
18390             }
18391             if(stat == TNG_FAILURE)
18392             {
18393                 continue;
18394             }
18395         }
18396         if(frame_set->first_frame != current_frame &&
18397            p_data->last_retrieved_frame >= 0)
18398         {
18399             data_frame = p_data->last_retrieved_frame + p_data->stride_length;
18400         }
18401         else
18402         {
18403             data_frame = p_data->first_frame_with_data;
18404         }
18405         frame_diff = data_frame - current_frame;
18406         if(frame_diff < 0)
18407         {
18408             continue;
18409         }
18410         if(min_diff == -1 || frame_diff <= min_diff)
18411         {
18412             if(frame_diff < min_diff)
18413             {
18414                 *n_data_blocks_in_next_frame = 1;
18415             }
18416             else
18417             {
18418                 *n_data_blocks_in_next_frame += 1;
18419             }
18420             if(n_requested_data_block_ids <= 0)
18421             {
18422                 size = sizeof(int64_t) * (*n_data_blocks_in_next_frame);
18423                 temp = realloc(*data_block_ids_in_next_frame, size);
18424                 if(!temp)
18425                 {
18426                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
18427                            sizeof(int64_t) * (*n_data_blocks_in_next_frame),
18428                            __FILE__, __LINE__);
18429                     free(*data_block_ids_in_next_frame);
18430                     *data_block_ids_in_next_frame = 0;
18431                     return(TNG_CRITICAL);
18432                 }
18433                 *data_block_ids_in_next_frame = temp;
18434             }
18435             else
18436             {
18437                 TNG_ASSERT(*n_data_blocks_in_next_frame <= n_requested_data_block_ids, "TNG library: Array of data block IDs out of bounds");
18438             }
18439             (*data_block_ids_in_next_frame)[(*n_data_blocks_in_next_frame) - 1] = block_id;
18440
18441             min_diff = frame_diff;
18442         }
18443     }
18444     for(i = 0; i < frame_set->n_data_blocks; i++)
18445     {
18446         np_data = &frame_set->tr_data[i];
18447         block_id = np_data->block_id;
18448
18449         if(n_requested_data_block_ids > 0)
18450         {
18451             found = 0;
18452             for(j = 0; j < n_requested_data_block_ids; j++)
18453             {
18454                 if(block_id == requested_data_block_ids[j])
18455                 {
18456                     found = 1;
18457                     break;
18458                 }
18459             }
18460             if(!found)
18461             {
18462                 continue;
18463             }
18464         }
18465
18466         if(!read_all && (np_data->last_retrieved_frame < frame_set->first_frame ||
18467            np_data->last_retrieved_frame >=
18468            frame_set->first_frame + frame_set->n_frames))
18469         {
18470             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data,
18471                                                                       TNG_USE_HASH, block_id);
18472             if(stat == TNG_CRITICAL)
18473             {
18474                 fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
18475                     __FILE__, __LINE__);
18476                 return(stat);
18477             }
18478             if(stat == TNG_FAILURE)
18479             {
18480                 continue;
18481             }
18482         }
18483         if(frame_set->first_frame != current_frame &&
18484            np_data->last_retrieved_frame >= 0)
18485         {
18486             data_frame = np_data->last_retrieved_frame + np_data->stride_length;
18487         }
18488         else
18489         {
18490             data_frame = np_data->first_frame_with_data;
18491         }
18492         frame_diff = data_frame - current_frame;
18493         if(frame_diff < 0)
18494         {
18495             continue;
18496         }
18497         if(min_diff == -1 || frame_diff <= min_diff)
18498         {
18499             if(frame_diff < min_diff)
18500             {
18501                 *n_data_blocks_in_next_frame = 1;
18502             }
18503             else
18504             {
18505                 *n_data_blocks_in_next_frame += 1;
18506             }
18507             if(n_requested_data_block_ids <= 0)
18508             {
18509                 size = sizeof(int64_t) * (*n_data_blocks_in_next_frame);
18510                 temp = realloc(*data_block_ids_in_next_frame, size);
18511                 if(!temp)
18512                 {
18513                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
18514                            sizeof(int64_t) * (*n_data_blocks_in_next_frame),
18515                            __FILE__, __LINE__);
18516                     free(*data_block_ids_in_next_frame);
18517                     *data_block_ids_in_next_frame = 0;
18518                     return(TNG_CRITICAL);
18519                 }
18520                 *data_block_ids_in_next_frame = temp;
18521             }
18522             else
18523             {
18524                 TNG_ASSERT(*n_data_blocks_in_next_frame <= n_requested_data_block_ids, "TNG library: Array of data block IDs out of bounds");
18525             }
18526             (*data_block_ids_in_next_frame)[(*n_data_blocks_in_next_frame) - 1] = block_id;
18527
18528             min_diff = frame_diff;
18529         }
18530     }
18531     if(min_diff < 0)
18532     {
18533         return(TNG_FAILURE);
18534     }
18535     *next_frame = current_frame + min_diff;
18536
18537     return(TNG_SUCCESS);
18538 }
18539
18540 /*
18541 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_all_data_block_types_get
18542                 (tng_trajectory_t tng_data,
18543                  int64_t *n_data_blocks,
18544                  int64_t **data_block_ids,
18545                  char ***data_block_names,
18546                  int64_t **stride_lengths,
18547                  int64_t **n_values_per_frame,
18548                  char **block_types,
18549                  char **dependencies,
18550                  char **compressions)
18551 {
18552     tng_gen_block_t block;
18553     long orig_file_pos, file_pos;
18554
18555     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18556     TNG_ASSERT(n_data_blocks, "TNG library: The pointer to n_data_blocks must not be NULL.");
18557     TNG_ASSERT(data_block_ids, "TNG library: The pointer to the list of data block IDs must not be NULL.");
18558     TNG_ASSERT(data_block_names, "TNG library: The pointer to the list of data block names must not be NULL.");
18559     TNG_ASSERT(stride_lengths, "TNG library: The pointer to the list of stride lengths must not be NULL.");
18560
18561     orig_file_pos = ftell(tng_data->input_file);
18562
18563     if(!tng_data->input_file_len)
18564     {
18565         fseek(tng_data->input_file, 0, SEEK_END);
18566         tng_data->input_file_len = ftell(tng_data->input_file);
18567     }
18568
18569     fseek(tng_data->input_file, 0, SEEK_SET);
18570     file_pos = 0;
18571
18572     *n_data_blocks = 0;
18573
18574     tng_block_init(&block);
18575
18576     while(file_pos < tng_data->input_file_len &&
18577           tng_block_header_read(tng_data, block) != TNG_CRITICAL)
18578     {
18579         if(block->id > TNG_TRAJECTORY_FRAME_SET)
18580         {
18581
18582         }
18583         file_pos += (long)(block->block_contents_size + block->header_contents_size);
18584         fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
18585     }
18586
18587     fseek(tng_data->input_file, orig_file_pos, SEEK_SET);
18588
18589     return(TNG_SUCCESS);
18590 }
18591 */
18592 tng_function_status DECLSPECDLLEXPORT tng_util_prepare_append_after_frame
18593                 (tng_trajectory_t tng_data,
18594                  const int64_t prev_frame)
18595 {
18596     tng_function_status stat;
18597     FILE *temp = tng_data->input_file;
18598
18599     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18600     TNG_ASSERT(prev_frame >= 0, "TNG library: The previous frame must not be negative.");
18601
18602     tng_data->input_file = tng_data->output_file;
18603
18604     stat = tng_frame_set_of_frame_find(tng_data, prev_frame);
18605     if(stat != TNG_SUCCESS)
18606     {
18607         return(stat);
18608     }
18609
18610     tng_data->current_trajectory_frame_set_output_file_pos =
18611     tng_data->current_trajectory_frame_set_input_file_pos;
18612
18613     tng_data->input_file = temp;
18614
18615     return(TNG_SUCCESS);
18616 }