Class: NADOLDisk

Inherits:
DSK
  • Object
show all
Defined in:
lib/NADOLDisk.rb

Constant Summary

Constants inherited from DSK

DSK::DSK_FILE_LENGTH, DSK::DSK_IMAGE_EXTENSIONS, DSK::FILE_SYSTEMS, DSK::INTERLEAVES, DSK::NIB_FILE_LENGTH, DSK::SECTOR_ORDERS

Instance Attribute Summary

Attributes inherited from DSK

#file_bytes, #sector_order, #source_filename, #track_count

Instance Method Summary collapse

Methods inherited from DSK

#best_subclass, create_new, #disassemble_sector, #dump_sector, #files, #get_block, #get_sector, #hex_dump, #is_cpm?, #is_dos33?, is_dsk_file?, #is_modified_dos?, #is_nadol?, #is_pascal?, #is_prodos?, read, #save_as, #set_boot_track

Constructor Details

#initialize(file_bytes, sector_order) ⇒ NADOLDisk

Returns a new instance of NADOLDisk.



39
40
41
42
# File 'lib/NADOLDisk.rb', line 39

def initialize(file_bytes,sector_order)
	super(file_bytes,sector_order)
	self.read_catalog
end

Instance Method Details

#add_file(file) ⇒ Object

add a file to the in-memory image of this DSK



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/NADOLDisk.rb', line 153

def add_file(file)
  raise "only NADOLFiles may be added to NADOL format disks!" unless file.kind_of?(NADOLFile)
  
 delete_file(file.filename) unless files[file.filename].nil?
 catalog_slot=find_catalog_slot(nil)
 raise "CATALOG IS FULL!" if catalog_slot.nil?
 
 free_sectors=free_sector_list
   
 sectors_needed=1+file.length_in_sectors
 raise "not enough free space - #{sectors_needed} sectors needed, #{free_sector_list.length} available " unless sectors_needed<=free_sectors.length
 
 #for each sector in the file, copy it to disk and then record it in the track/sector list
 track_sector_list="\0"*256
 track_sector_list_sector=free_sectors[0]
 (0..sectors_needed-2).each do |sector_in_file|
   sector_to_use=free_sectors[sector_in_file+1]
   track_sector_list[sector_in_file*2]=sector_to_use.track_no
   track_sector_list[(sector_in_file*2)+1]=sector_to_use.sector_no
   sector_contents=file.contents[(sector_in_file*256)..(sector_in_file*256)+255] || ""
   set_sector(sector_to_use.track_no,sector_to_use.sector_no,sector_contents)
 end
 #write the track/sector list
 set_sector(track_sector_list_sector.track_no,track_sector_list_sector.sector_no,track_sector_list)
 
 #update the catalog
 catalog_sector=get_sector(catalog_slot.track_no,catalog_slot.sector_no)
 catalog_sector[catalog_slot.offset..catalog_slot.offset+0x0B]=file.catalog_filename
 catalog_sector[catalog_slot.offset+0x0C]=file.contents.length % 0x100
 catalog_sector[catalog_slot.offset+0x0D]=file.contents.length / 0x100
 catalog_sector[catalog_slot.offset+0x0E]=track_sector_list_sector.track_no
 catalog_sector[catalog_slot.offset+0x0F]=track_sector_list_sector.sector_no
 set_sector(catalog_slot.track_no,catalog_slot.sector_no,catalog_sector)
 
 raise "catalog not updated correctly!" if find_catalog_slot(file.filename).nil?
 #reread the catalog to populate the files list
 read_catalog
end

#delete_file(filename) ⇒ Object



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/NADOLDisk.rb', line 113

def delete_file(filename)
  this_files_catalog_slot=find_catalog_slot(filename)    
  #if file not in catalog, do nothing
  return if this_files_catalog_slot.nil? 
  file_descriptive_entry=get_sector(this_files_catalog_slot.track_no,this_files_catalog_slot.sector_no)[this_files_catalog_slot.offset..this_files_catalog_slot.offset+0x0f]
  
  #mark sector as free in sector usage list
  sector_usage_bitmap_sector=get_sector(0,2)  
  sectors_to_mark_available=get_track_sector_list(file_descriptive_entry[0x0E],file_descriptive_entry[0x0F])
  sectors_to_mark_available<<DSKTrackSector.new(file_descriptive_entry[0x0E],file_descriptive_entry[0x0F])
  sectors_to_mark_available.each do |ts|
    offset_of_byte_containing_this_sector=0x20+(ts.track_no*2)+(ts.sector_no/8)
    byte_containing_this_sector=sector_usage_bitmap_sector[offset_of_byte_containing_this_sector]
    byte_containing_this_sector=byte_containing_this_sector&(0xff-(2**(7-(ts.sector_no%8))))
    sector_usage_bitmap_sector[offset_of_byte_containing_this_sector]=byte_containing_this_sector
  end
  set_sector(0,2,sector_usage_bitmap_sector)
  
  #mark slot as available in catalog
  catalog_sector=get_sector(this_files_catalog_slot.track_no,this_files_catalog_slot.sector_no)
  catalog_sector[this_files_catalog_slot.offset]=0xFF
  set_sector(this_files_catalog_slot.track_no,this_files_catalog_slot.sector_no,catalog_sector)
end

#dump_catalogObject



30
31
32
33
34
35
36
37
# File 'lib/NADOLDisk.rb', line 30

def dump_catalog
	s=""
	files.keys.sort.each { |file_name|		
		file=files[file_name]	
		s<< "#{sprintf('% 6d',file.contents.length)} #{file.filename}\n"
	}
	s
end

#file_systemObject



44
45
46
# File 'lib/NADOLDisk.rb', line 44

def file_system
	:nadol
end

#find_catalog_slot(filename) ⇒ Object

iterate through the CATALOG to find either the named file or (if nil is passed in) an empty slot



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/NADOLDisk.rb', line 66

def find_catalog_slot(filename)
  track=0
  sector=3
  catalog_filename=NADOLFile.catalog_filename(filename.upcase) unless filename.nil?
  while (sector<=9) do
    sector_data=get_sector(track,sector)
    (0..15).each do |slot_no|
      slot_start=slot_no*0x10
      if (filename.nil? && (sector_data[slot_start]==0x00)|| (sector_data[slot_start]==0xFF)) then
        return DSKTrackSector.new(track,sector,slot_start)
      end
      if (!filename.nil?) && (sector_data[slot_start..slot_start+0x0B]==catalog_filename) then
        return DSKTrackSector.new(track,sector,slot_start)
      end
    end
    sector+=1
  end
  nil
end

#free_sector_listObject

iterate through the sector usage bitmap, return a list of [track,sector] for sectors marked available



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/NADOLDisk.rb', line 87

def free_sector_list  
  sector_usage_bitmap=get_sector(0,2)[0x20..0x65]
   free_sectors=[]
    (0..(sector_usage_bitmap.length/2)-1).each do |track|
      track_bitmap_lo=sector_usage_bitmap[track*2]
      track_bitmap_hi=sector_usage_bitmap[1+track*2]
      (0..7).each do |sector|
        if ((track_bitmap_lo & (2**(7-sector)))==0) then
          free_sectors<<DSKTrackSector.new(track,sector)
        end
        if ((track_bitmap_hi & (2**(7-sector)))==0) then
          free_sectors<<DSKTrackSector.new(track,sector+8)
        end        
      end
    end
    free_sectors.sort  
end

#get_track_sector_list(ts_list_track_no, ts_list_sector_no) ⇒ Object

given a track and sector, treat it as a track/sector list and return an array containing track/sector pairs



139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/NADOLDisk.rb', line 139

def get_track_sector_list(ts_list_track_no,ts_list_sector_no)
  ts_list_sector=get_sector(ts_list_track_no,ts_list_sector_no)
  ts_list=[]
  for entry_number in 0..0x7f    
    data_track_no=ts_list_sector[entry_number*2]
    data_sector_no=ts_list_sector[entry_number*2+1]
    if( (data_track_no!=0 || data_sector_no!=0)  && data_track_no<track_count && data_sector_no<=0x0f) then
      ts_list<<DSKTrackSector.new(data_track_no,data_sector_no)
    end
  end
  ts_list
end

#make_file(filename, contents, file_options = {}) ⇒ Object



105
106
107
108
109
110
111
# File 'lib/NADOLDisk.rb', line 105

def make_file(filename,contents,file_options={})
  if (file_options[:tokenise]) then
    return NADOLTokenisedFile.new(filename,NADOLTokenisedFile.tokenise(contents))  
  else
    return NADOLFile.new(filename,contents)
  end
end

#read_catalogObject

reads the catalog, and populate the “files” array with files CATALOG will be at track $00, sector $03 to track $00, sector $09 each entry consists of $10 bytes, which are: 00-0B - filename - if file is deleted, first byte will be FF 0C-0D - filesize (low byte first) 0E - track of track sector list sector 0F - sector of track sector list sector



199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/NADOLDisk.rb', line 199

def read_catalog
  @files={}
  track=0
  sector=3
  while (sector<=9) do
    sector_data=get_sector(track,sector)
    (0..15).each do |slot_no|
      slot_offset=slot_no*0x10
      file_descriptive_entry=sector_data[slot_offset..slot_offset+0x10]
      if (file_descriptive_entry[0]!=0xFF && file_descriptive_entry[0]!=0x00) then # skip deleted /empty files
        filename=""
        file_descriptive_entry[0..11].to_s.each_byte{|b| filename+=(b.%128).chr} #strip off high bit
        filename.sub!(/ *$/,"") #strip off trailing spaces
        file_size=file_descriptive_entry[0x0D]*256+file_descriptive_entry[0x0C]
        if (file_size>0) then
          contents=""	
          get_track_sector_list(file_descriptive_entry[0x0E],file_descriptive_entry[0x0F]).each do |ts|
            contents<<get_sector(ts.track_no,ts.sector_no)
          end
          contents=contents[0..file_size-1]
          if (NADOLTokenisedFile.can_be_nadol_tokenised_file?(contents)) then
            @files[filename]= NADOLTokenisedFile.new(filename,contents)
          else
            @files[filename]= NADOLBinaryFile.new(filename,contents)
          end
        end
      end
    end
  sector+=1
  end
end

#set_sector(track, sector, contents) ⇒ Object



49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/NADOLDisk.rb', line 49

def set_sector(track,sector,contents)
  super(track,sector,contents)  
  
  #now mark sector as used in sector usage list
  #don't bother marking the 'system' sectors used
  if ((track>0) || (sector>9)) then
    sector_usage_bitmap_sector=get_sector(0,2)  
    offset_of_byte_containing_this_sector=0x20+(track*2)+(sector/8)
    byte_containing_this_sector=sector_usage_bitmap_sector[offset_of_byte_containing_this_sector]
    byte_containing_this_sector=byte_containing_this_sector|(2**(7-(sector%8)))
    sector_usage_bitmap_sector[offset_of_byte_containing_this_sector]=byte_containing_this_sector
    set_sector(0,2,sector_usage_bitmap_sector)
  end
end