/////////////////////////////////////////////////////////////////////////////// // Saves BAS file public bool Save(Stream in_stream, ProgramStorage in_storage) { Encoding encoding; // set open options based on encoding type switch (Encoding) { case EncodingType.Ansi: encoding = new ASCIIEncoding(); break; case EncodingType.Auto: case EncodingType.Utf8: encoding = new UTF8Encoding(); break; case EncodingType.Unicode: encoding = new UnicodeEncoding(); break; default: encoding = null; break; } using (StreamWriter bas_file = new StreamWriter(in_stream, encoding)) { // start processing of the memory int current_pos = 0; int next_line_pos = 0; int line_data_end; StatusCode state = StatusCode.Tokenizing; BasicLineHeader current_line = new BasicLineHeader(); current_line.ReadFromMemory(current_pos, in_storage); while (current_pos < in_storage.Length && current_line.Length != BAS_PRGEND) { // check basic format if (current_line.Length < BasicLineHeader.Size) { bas_file.Write("\n*** Broken BASIC program\n"); break; } // set next line pointer next_line_pos = current_pos + current_line.Length; // write line number bas_file.Write("{0,4:d} ", current_line.Number); // decode line current_pos += BasicLineHeader.Size; line_data_end = next_line_pos; if (current_pos <= line_data_end - 1 && in_storage.Data[line_data_end - 1] == BAS_LINEND) { line_data_end--; } state = StatusCode.Tokenizing; while (current_pos < line_data_end) { char current_char = (char)in_storage.Data[current_pos]; // decode token or character if (state == StatusCode.Tokenizing) { // store tokenized item if (Encoding == EncodingType.Ansi) { bas_file.Write(m_ansi_tokenized_map[current_char]); } else { bas_file.Write(m_unicode_tokenized_map[current_char]); } } else { // store non tokenized item if (Encoding == EncodingType.Ansi) { if (current_char < 0x80) { bas_file.Write(m_ansi_tokenized_map[current_char]); } else { bas_file.Write("\\x{0:X2}", current_char); } } else { if (current_char < 0x80) { bas_file.Write(m_unicode_tokenized_map[current_char]); } else { bas_file.Write("\\x{0:X2}", current_char); } } } // update status if (current_char == '"') { state ^= StatusCode.Quotation; } else { if (!state.HasFlag(StatusCode.Quotation)) { if (current_char == BAS_TOKEN_DATA) { state |= StatusCode.Data; } else { if (current_char == BAS_TOKEN_COLON) { state &= ~StatusCode.Data; } else { if (current_char == BAS_TOKEN_COMMENT || current_char == BAS_TOKEN_REM) { state |= StatusCode.Remark; } } } } } current_pos++; } bas_file.WriteLine(); current_pos = next_line_pos; current_line.ReadFromMemory(current_pos, in_storage); } // write remaining data offset int remaining_byte_index = current_pos + 1; // +1 beacuse of the BAS_PRGEND byte if (remaining_byte_index < in_storage.Length) { bas_file.WriteLine("BYTESOFFSET {0}", remaining_byte_index); } // write remaining data int bytes_in_a_line = 0; while (remaining_byte_index < in_storage.Length) { if (bytes_in_a_line == 0) { bas_file.Write("BYTES "); } bas_file.Write("\\x{0:X2}", in_storage.Data[remaining_byte_index]); remaining_byte_index++; bytes_in_a_line++; // write new line if (bytes_in_a_line > MAX_BYTES_IN_A_LINE) { bas_file.WriteLine(); bytes_in_a_line = 0; } } // new line if (bytes_in_a_line > 0) { bas_file.WriteLine(); } // write autostart if (in_storage.AutoStart) { bas_file.WriteLine("AUTOSTART"); } } return(true); }