1 /******************************************************************************
2 
3   Copyright (c) 2003-2007 Turku PET Centre
4 
5   Library:     ecat7ml.c
6   Description: Reading and writing ECAT 7.x matrix list.
7 
8   This library is free software; you can redistribute it and/or
9   modify it under the terms of the GNU Lesser General Public
10   License as published by the Free Software Foundation; either
11   version 2.1 of the License, or (at your option) any later version.
12 
13   This library is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16   See the GNU Lesser General Public License for more details:
17   http://www.gnu.org/copyleft/lesser.html
18 
19   You should have received a copy of the GNU Lesser General Public License
20   along with this library/program; if not, write to the Free Software
21   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 
23   Turku PET Centre, Turku, Finland, http://www.turkupetcentre.fi/
24 
25   Modification history:
26   2003-07-21 Vesa Oikonen
27     First created.
28   2004-06-20 VO
29     ecat7PrintMatlist(): blkNr is printed correctly (+1).
30   2004-06-27 VO
31     Included ecat7DeleteLateFrames().
32   2007-02-27 VO
33     Added functions ecat7GetMatrixBlockSize() and ecat7GetPlaneAndFrameNr().
34   2007-03-13 VO
35     Added functions ecat7GetNums() and ecat7GatherMatlist().
36   2007-17-07 Harri Merisaari
37     fixed for ANSI
38 
39 ******************************************************************************/
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <math.h>
43 #include <ctype.h>
44 #include <string.h>
45 #include <unistd.h>
46 #include <time.h>
47 /*****************************************************************************/
48 #include "swap.h"
49 #include "ecat7.h"
50 /*****************************************************************************/
51 
52 /*****************************************************************************/
53 /*!
54  * Prepare matrix list for additional matrix data and return block number
55  * for matrix header. Directory records are written in big endian byte order.
56  * Set block_nr to the number of data blocks + (nr of header blocks - 1)
57  *
58  * @param fp file pointer
59  * @param matrix_id matrix identifier coding
60  * @param block_nr matrix number [1..number of matrixes]
61  * @return returns the block number for matrix header, -1 if invalid input,
62  * -2 if first directory block is not found, -3 if failed to read first block,
63  * -9 if other directory block is not found, -10 if failed to read other block,
64  * -11 if place for new directory block is not found, -12 if failed clear new
65  * block, -15 if place for new directory block is not found, -16 if failed to
66  * write into new block
67  */
ecat7EnterMatrix(FILE * fp,int matrix_id,int block_nr)68 int ecat7EnterMatrix(FILE *fp, int matrix_id, int block_nr) {
69   unsigned int i=0, dirblk, little, busy=1, nxtblk=0, oldsize;
70   /*unsigned*/ int dirbuf[MatBLKSIZE/4];
71 
72   if(ECAT7_TEST) printf("ecat7EnterMatrix(fp, %d, %d)\n", matrix_id, block_nr);
73   /* Check the input */
74   if(fp==NULL || matrix_id<1 || block_nr<1) return(-1);
75   /* Is this a little endian machine? */
76   little=little_endian();
77   /* Read first directory record block */
78   dirblk=MatFirstDirBlk;
79   fseek(fp, (dirblk-1)*MatBLKSIZE, SEEK_SET);
80   if(ftell(fp)!=(dirblk-1)*MatBLKSIZE) return(-2);
81   if(fread(dirbuf, sizeof(int), MatBLKSIZE/4, fp) != MatBLKSIZE/4) return(-3);
82   /* Byte order conversion for ints in little endian platforms */
83   if(little) swawbip(dirbuf, MatBLKSIZE);
84   /* Read through the existing directory records */
85   while(busy) {
86     /* Go through the directory entries in this record */
87     for(i=4, nxtblk=dirblk+1; i<MatBLKSIZE/4; i+=4) {
88       oldsize=dirbuf[i+2]-dirbuf[i+1]+1;
89       if(dirbuf[i]==0) {  /* Check for end of matrix list */
90         busy=0; break;
91       } else if(dirbuf[i]==matrix_id) {  /* Maybe this matrix already exists? */
92         /* yes it does; is old data smaller? */
93         if(oldsize<block_nr) {
94           /* it was smaller, so do not use it, but mark it deleted */
95           dirbuf[i] = 0xFFFFFFFF; dirbuf[i+3]=-1;
96           if(little) swawbip(dirbuf, MatBLKSIZE);
97           fseek(fp, (dirblk-1)*MatBLKSIZE, SEEK_SET);
98           if(ftell(fp)!=(dirblk-1)*MatBLKSIZE) return(-6);
99           if(fwrite(dirbuf, sizeof(int), MatBLKSIZE/4, fp) != MatBLKSIZE/4) return(-7);
100           if(little) swawbip(dirbuf, MatBLKSIZE);
101           nxtblk=dirbuf[i+2]+1;
102         } else { /* old matrix size is ok */
103           nxtblk=dirbuf[i+1]; dirbuf[0]++; dirbuf[3]--; busy=0;
104           break;
105         }
106       } else { /* this is not the same matrix */
107         /* But is deleted and of same or smaller size? */
108         if(dirbuf[i+3]==-1 && block_nr<=oldsize) {
109           /* yes it was, so lets recycle it */
110           dirbuf[i]=matrix_id;
111           nxtblk=dirbuf[i+1]; dirbuf[0]++; dirbuf[3]--; busy=0;
112           break;
113         }
114         /* nothing to be done with this entry */
115         nxtblk=dirbuf[i+2]+1;
116       }
117     } /* next entry in this record */
118     if(!busy) break; /* stop reading existing records */
119     /* Read the next directory record */
120     if(dirbuf[1]!=MatFirstDirBlk) {
121       /* There are more records left to read */
122       dirblk=dirbuf[1];
123       fseek(fp, (dirblk-1)*MatBLKSIZE, SEEK_SET);
124       if(ftell(fp)!=(dirblk-1)*MatBLKSIZE) return(-9);
125       if(fread(dirbuf, sizeof(int), MatBLKSIZE/4, fp) != MatBLKSIZE/4) return(-10);
126       if(little) swawbip(dirbuf, MatBLKSIZE);
127     } else {
128       /* No more records to read, so lets write a new empty one */
129       dirbuf[1]=nxtblk; /* write a pointer to the new one */
130       if(little) swawbip(dirbuf, MatBLKSIZE);
131       fseek(fp, (dirblk-1)*MatBLKSIZE, SEEK_SET);
132       if(ftell(fp)!=(dirblk-1)*MatBLKSIZE) return(-11);
133       if(fwrite(dirbuf, sizeof(int), MatBLKSIZE/4, fp) != MatBLKSIZE/4) return(-12);
134       /* and then initiate the contents of the next one, but do not write it */
135       dirbuf[0]=31; dirbuf[1]=MatFirstDirBlk; dirbuf[2]=dirblk;
136       dirbuf[3]=0; dirblk=nxtblk;
137       for(i=4; i<MatBLKSIZE/4; i++) dirbuf[i]=0;
138     }
139   } /* next directory record */
140   dirbuf[i]=matrix_id;
141   dirbuf[i+1]=nxtblk;
142   dirbuf[i+2]=nxtblk+block_nr;
143   dirbuf[i+3]=1; /* mark the entry as read/write */
144   dirbuf[0]--;
145   dirbuf[3]++;
146   if(little) swawbip(dirbuf, MatBLKSIZE);
147   fseek(fp, (dirblk-1)*MatBLKSIZE, SEEK_SET);
148   if(ftell(fp)!=(dirblk-1)*MatBLKSIZE) return(-15);
149   if(fwrite(dirbuf, sizeof(int), MatBLKSIZE/4, fp) != MatBLKSIZE/4) return(-16);
150   if(ECAT7_TEST) printf("returning %d from ecat7EnterMatrix()\n", nxtblk);
151   return(nxtblk);
152 }
153